From 3011c62beab224af9190a687d30a11d115abe5d9 Mon Sep 17 00:00:00 2001 From: OlegZv <19969581+OlegZv@users.noreply.github.com> Date: Sat, 31 May 2025 23:28:55 -0400 Subject: [PATCH 1/7] chore: Update release action to dispatch and deploy to "on release" --- .github/workflows/deploy.yml | 27 ++++++++++++++++----------- .github/workflows/release.yml | 17 +++++++++-------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b3a0fa5..7364d62 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,20 +1,25 @@ -name: Deploy +name: Deploy to PyPI on: - workflow_dispatch: + release: + types: + - published jobs: - release: + deploy: runs-on: ubuntu-latest + permissions: + id-token: write + steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.8' - - run: make install-dev - - run: make build - - run: make test-install-build - - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} - run: make deploy + + - name: Build the distribution + run: make build + - name: Install the package + run: make test-install-build + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f9f33df..d589497 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,9 +1,7 @@ -name: Release +name: Create Release on: - push: - branches: - - 'main' + workflow_dispatch: jobs: release: @@ -12,10 +10,13 @@ jobs: - uses: actions/checkout@v4 with: persist-credentials: false - - uses: pnpm/action-setup@v2 + - name: Set up pnpm + uses: pnpm/action-setup@v2 with: version: 8 - - run: pnpm install - - env: + - name: Install dependencies + run: pnpm install + - name: Generate a release + env: GITHUB_TOKEN: ${{ secrets.CLI_PAT }} - run: pnpm run release + run: pnpm run release \ No newline at end of file From 94155dbe05c23ba12b9c87640c10d1330f89aabf Mon Sep 17 00:00:00 2001 From: OlegZv <19969581+OlegZv@users.noreply.github.com> Date: Sun, 1 Jun 2025 01:08:34 -0400 Subject: [PATCH 2/7] test: Fix tests for pydantic 2.11.0 changes to always include "additionalProperties" --- .pre-commit-config.yaml | 2 +- tests/test_simple.py | 1 + tests/test_websocket.py | 1 + tests/test_with_root_path.py | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4e71f76..3f1c60c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: - id: trailing-whitespace - id: no-commit-to-branch - repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook - rev: v9.5.0 + rev: v9.22.0 hooks: - id: commitlint stages: [commit-msg] diff --git a/tests/test_simple.py b/tests/test_simple.py index 174077f..10a4423 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -783,6 +783,7 @@ def test_simple_example(self) -> None: 'content': { 'application/json': { 'schema': { + 'additionalProperties': True, 'type': 'object', 'title': 'Response Get Versions Versions Get' } diff --git a/tests/test_websocket.py b/tests/test_websocket.py index 0213375..3c05ab4 100644 --- a/tests/test_websocket.py +++ b/tests/test_websocket.py @@ -175,6 +175,7 @@ def test_simple_example(self) -> None: 'content': { 'application/json': { 'schema': { + 'additionalProperties': True, 'type': 'object', 'title': 'Response Get Versions Versions Get' } diff --git a/tests/test_with_root_path.py b/tests/test_with_root_path.py index 7613d50..5f6fad8 100644 --- a/tests/test_with_root_path.py +++ b/tests/test_with_root_path.py @@ -136,6 +136,7 @@ def test_with_root_path_example(self) -> None: 'content': { 'application/json': { 'schema': { + 'additionalProperties': True, 'type': 'object', 'title': 'Response Get Versions Versions Get' } From 5428f79aa57a3fbd2be1dbdca66a1d10ee0b1247 Mon Sep 17 00:00:00 2001 From: OlegZv <19969581+OlegZv@users.noreply.github.com> Date: Sun, 1 Jun 2025 01:30:00 -0400 Subject: [PATCH 3/7] test: Fix tests for pydantic 2.11.0 changes to always include "additionalProperties" --- tests/test_simple.py | 20 +++++++++++++------- tests/test_websocket.py | 14 ++++++++++---- tests/test_with_root_path.py | 14 ++++++++++---- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/tests/test_simple.py b/tests/test_simple.py index 10a4423..c3d5d59 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -1,6 +1,8 @@ from fastapi.testclient import TestClient from unittest import TestCase + +import pydantic from examples.simple import app, versions @@ -134,10 +136,7 @@ def test_simple_example(self) -> None: self.assertEqual(200, test_client.get('/v1/swagger').status_code) self.assertEqual(200, test_client.get('/v2/swagger').status_code) self.assertEqual(200, test_client.get('/latest/swagger').status_code) - - # openapi - self.assertDictEqual( - { + expected_response = { 'openapi': '3.1.0', 'info': { 'title': 'test', @@ -783,7 +782,6 @@ def test_simple_example(self) -> None: 'content': { 'application/json': { 'schema': { - 'additionalProperties': True, 'type': 'object', 'title': 'Response Get Versions Versions Get' } @@ -926,8 +924,16 @@ def test_simple_example(self) -> None: } } } - }, - test_client.get('/api_schema.json').json() + } + if pydantic.__version__ >= "2.11.0": + # added 'additionalProperties': True in the /versions API + expected_response["paths"]["/versions"]["get"]["responses"]["200"][ + "content" + ]["application/json"]["schema"]["additionalProperties"] = True + # openapi + self.assertDictEqual( + expected_response, + test_client.get('/api_schema.json').json() ) self.assertDictEqual( { diff --git a/tests/test_websocket.py b/tests/test_websocket.py index 3c05ab4..b248b0e 100644 --- a/tests/test_websocket.py +++ b/tests/test_websocket.py @@ -1,3 +1,4 @@ +import pydantic from fastapi import WebSocketDisconnect from fastapi.testclient import TestClient @@ -85,8 +86,7 @@ def test_simple_example(self) -> None: self.assertEqual(200, test_client.get('/latest/swagger').status_code) # openapi - self.assertDictEqual( - { + expected_response = { 'openapi': '3.1.0', 'info': { 'title': 'test', @@ -175,7 +175,6 @@ def test_simple_example(self) -> None: 'content': { 'application/json': { 'schema': { - 'additionalProperties': True, 'type': 'object', 'title': 'Response Get Versions Versions Get' } @@ -186,7 +185,14 @@ def test_simple_example(self) -> None: } } } - }, + } + if pydantic.__version__ >= "2.11.0": + # added 'additionalProperties': True in the /versions API + expected_response["paths"]["/versions"]["get"]["responses"]["200"][ + "content" + ]["application/json"]["schema"]["additionalProperties"] = True + self.assertDictEqual( + expected_response, test_client.get('/api_schema.json').json() ) self.assertDictEqual( diff --git a/tests/test_with_root_path.py b/tests/test_with_root_path.py index 5f6fad8..9a3e577 100644 --- a/tests/test_with_root_path.py +++ b/tests/test_with_root_path.py @@ -1,3 +1,4 @@ +import pydantic from fastapi.testclient import TestClient from unittest import TestCase @@ -44,8 +45,7 @@ def test_with_root_path_example(self) -> None: self.assertEqual(200, test_client.get('/latest/swagger').status_code) # openapi - self.assertDictEqual( - { + expected_response = { 'openapi': '3.1.0', 'info': { 'title': 'test', @@ -136,7 +136,6 @@ def test_with_root_path_example(self) -> None: 'content': { 'application/json': { 'schema': { - 'additionalProperties': True, 'type': 'object', 'title': 'Response Get Versions Versions Get' } @@ -147,7 +146,14 @@ def test_with_root_path_example(self) -> None: } } } - }, + } + if pydantic.__version__ >= "2.11.0": + # added 'additionalProperties': True in the /versions API + expected_response["paths"]["/versions"]["get"]["responses"]["200"][ + "content" + ]["application/json"]["schema"]["additionalProperties"] = True + self.assertDictEqual( + expected_response, test_client.get('/api/api_schema.json').json() ) self.assertDictEqual( From 7a27062f7eff6d082a2585d89c18b0fd2452b9bd Mon Sep 17 00:00:00 2001 From: OlegZv <19969581+OlegZv@users.noreply.github.com> Date: Sun, 1 Jun 2025 01:37:23 -0400 Subject: [PATCH 4/7] chore: Linter fixes --- tests/test_simple.py | 1260 +++++++++++++++++----------------- tests/test_websocket.py | 164 ++--- tests/test_with_root_path.py | 164 ++--- 3 files changed, 794 insertions(+), 794 deletions(-) diff --git a/tests/test_simple.py b/tests/test_simple.py index c3d5d59..9b8f0ae 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -136,804 +136,804 @@ def test_simple_example(self) -> None: self.assertEqual(200, test_client.get('/v1/swagger').status_code) self.assertEqual(200, test_client.get('/v2/swagger').status_code) self.assertEqual(200, test_client.get('/latest/swagger').status_code) - expected_response = { - 'openapi': '3.1.0', - 'info': { - 'title': 'test', - 'description': 'Simple example of FastAPI Versionizer.', - 'termsOfService': 'https://github.com/alexschimpf/fastapi-versionizer', - 'version': '0.1.0' - }, - 'paths': { - '/v1/items': { - 'get': { - 'tags': [ - 'Items' - ], - 'summary': 'Get Items', - 'operationId': 'get_items_v1_items_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'items': { - '$ref': '#/components/schemas/Item' - }, - 'type': 'array', - 'title': 'Response Get Items V1 Items Get' - } + expected_response = { + 'openapi': '3.1.0', + 'info': { + 'title': 'test', + 'description': 'Simple example of FastAPI Versionizer.', + 'termsOfService': 'https://github.com/alexschimpf/fastapi-versionizer', + 'version': '0.1.0' + }, + 'paths': { + '/v1/items': { + 'get': { + 'tags': [ + 'Items' + ], + 'summary': 'Get Items', + 'operationId': 'get_items_v1_items_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'items': { + '$ref': '#/components/schemas/Item' + }, + 'type': 'array', + 'title': 'Response Get Items V1 Items Get' } } } + } + }, + 'deprecated': True + }, + 'post': { + 'tags': [ + 'Items' + ], + 'summary': 'Create Item', + 'operationId': 'create_item_v1_items_post', + 'requestBody': { + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/Item' + } + } }, - 'deprecated': True + 'required': True }, - 'post': { - 'tags': [ - 'Items' - ], - 'summary': 'Create Item', - 'operationId': 'create_item_v1_items_post', - 'requestBody': { + 'responses': { + '200': { + 'description': 'Successful Response', 'content': { 'application/json': { 'schema': { '$ref': '#/components/schemas/Item' } } - }, - 'required': True + } }, - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/Item' - } + '422': { + 'description': 'Validation Error', + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/HTTPValidationError' } } - }, - '422': { - 'description': 'Validation Error', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/HTTPValidationError' - } + } + } + }, + 'deprecated': True + } + }, + '/v1/items/{item_id}': { + 'get': { + 'tags': [ + 'Items' + ], + 'summary': 'Get Item', + 'operationId': 'get_item_v1_items__item_id__get', + 'deprecated': True, + 'parameters': [ + { + 'name': 'item_id', + 'in': 'path', + 'required': True, + 'schema': { + 'type': 'integer', + 'title': 'Item Id' + } + } + ], + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/Item' } } } }, - 'deprecated': True - } - }, - '/v1/items/{item_id}': { - 'get': { - 'tags': [ - 'Items' - ], - 'summary': 'Get Item', - 'operationId': 'get_item_v1_items__item_id__get', - 'deprecated': True, - 'parameters': [ - { - 'name': 'item_id', - 'in': 'path', - 'required': True, - 'schema': { - 'type': 'integer', - 'title': 'Item Id' - } - } - ], - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/Item' - } + '422': { + 'description': 'Validation Error', + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/HTTPValidationError' } } - }, - '422': { - 'description': 'Validation Error', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/HTTPValidationError' - } + } + } + } + } + }, + '/v1/status': { + 'get': { + 'tags': [ + 'Status' + ], + 'summary': 'Get Status', + 'operationId': 'get_status_v1_status_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'type': 'string', + 'title': 'Response Get Status V1 Status Get' } } } } } - }, - '/v1/status': { - 'get': { - 'tags': [ - 'Status' - ], - 'summary': 'Get Status', - 'operationId': 'get_status_v1_status_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'type': 'string', - 'title': 'Response Get Status V1 Status Get' - } + } + }, + '/v1/users': { + 'get': { + 'tags': [ + 'Users' + ], + 'summary': 'Get Users', + 'operationId': 'get_users_v1_users_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'items': { + '$ref': '#/components/schemas/User' + }, + 'type': 'array', + 'title': 'Response Get Users V1 Users Get' } } } } - } + }, + 'deprecated': True }, - '/v1/users': { - 'get': { - 'tags': [ - 'Users' - ], - 'summary': 'Get Users', - 'operationId': 'get_users_v1_users_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'items': { - '$ref': '#/components/schemas/User' - }, - 'type': 'array', - 'title': 'Response Get Users V1 Users Get' - } - } + 'post': { + 'tags': [ + 'Users' + ], + 'summary': 'Create User', + 'operationId': 'create_user_v1_users_post', + 'requestBody': { + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/User' } } }, - 'deprecated': True + 'required': True }, - 'post': { - 'tags': [ - 'Users' - ], - 'summary': 'Create User', - 'operationId': 'create_user_v1_users_post', - 'requestBody': { + 'responses': { + '200': { + 'description': 'Successful Response', 'content': { 'application/json': { 'schema': { '$ref': '#/components/schemas/User' } } - }, - 'required': True + } }, - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/User' - } + '422': { + 'description': 'Validation Error', + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/HTTPValidationError' } } - }, - '422': { - 'description': 'Validation Error', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/HTTPValidationError' - } + } + } + }, + 'deprecated': True + } + }, + '/v1/users/{user_id}': { + 'get': { + 'tags': [ + 'Users' + ], + 'summary': 'Get User', + 'operationId': 'get_user_v1_users__user_id__get', + 'deprecated': True, + 'parameters': [ + { + 'name': 'user_id', + 'in': 'path', + 'required': True, + 'schema': { + 'type': 'integer', + 'title': 'User Id' + } + } + ], + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/User' } } } }, - 'deprecated': True + '422': { + 'description': 'Validation Error', + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/HTTPValidationError' + } + } + } + } + } + } + }, + '/v2/items': { + 'get': { + 'tags': [ + 'Items' + ], + 'summary': 'Get Items V2', + 'operationId': 'get_items_v2_v2_items_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'items': { + '$ref': '#/components/schemas/ItemV2' + }, + 'type': 'array', + 'title': 'Response Get Items V2 V2 Items Get' + } + } + } + } } }, - '/v1/users/{user_id}': { - 'get': { - 'tags': [ - 'Users' - ], - 'summary': 'Get User', - 'operationId': 'get_user_v1_users__user_id__get', - 'deprecated': True, - 'parameters': [ - { - 'name': 'user_id', - 'in': 'path', - 'required': True, + 'post': { + 'tags': [ + 'Items' + ], + 'summary': 'Create Item V2', + 'operationId': 'create_item_v2_v2_items_post', + 'requestBody': { + 'content': { + 'application/json': { 'schema': { - 'type': 'integer', - 'title': 'User Id' + '$ref': '#/components/schemas/ItemV2' } } - ], - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/User' - } - } - } - }, - '422': { - 'description': 'Validation Error', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/HTTPValidationError' - } - } - } - } - } - } - }, - '/v2/items': { - 'get': { - 'tags': [ - 'Items' - ], - 'summary': 'Get Items V2', - 'operationId': 'get_items_v2_v2_items_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'items': { - '$ref': '#/components/schemas/ItemV2' - }, - 'type': 'array', - 'title': 'Response Get Items V2 V2 Items Get' - } - } - } - } - } + }, + 'required': True }, - 'post': { - 'tags': [ - 'Items' - ], - 'summary': 'Create Item V2', - 'operationId': 'create_item_v2_v2_items_post', - 'requestBody': { + 'responses': { + '200': { + 'description': 'Successful Response', 'content': { 'application/json': { 'schema': { '$ref': '#/components/schemas/ItemV2' } } - }, - 'required': True + } }, - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/ItemV2' - } + '422': { + 'description': 'Validation Error', + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/HTTPValidationError' } } - }, - '422': { - 'description': 'Validation Error', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/HTTPValidationError' - } + } + } + } + } + }, + '/v2/status': { + 'get': { + 'tags': [ + 'Status' + ], + 'summary': 'Get Status', + 'operationId': 'get_status_v2_status_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'type': 'string', + 'title': 'Response Get Status V2 Status Get' } } } } } - }, - '/v2/status': { - 'get': { - 'tags': [ - 'Status' - ], - 'summary': 'Get Status', - 'operationId': 'get_status_v2_status_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'type': 'string', - 'title': 'Response Get Status V2 Status Get' - } + } + }, + '/v2/users': { + 'get': { + 'tags': [ + 'Users' + ], + 'summary': 'Get Users V2', + 'operationId': 'get_users_v2_v2_users_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'items': { + '$ref': '#/components/schemas/UserV2' + }, + 'type': 'array', + 'title': 'Response Get Users V2 V2 Users Get' } } } } } }, - '/v2/users': { - 'get': { - 'tags': [ - 'Users' - ], - 'summary': 'Get Users V2', - 'operationId': 'get_users_v2_v2_users_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'items': { - '$ref': '#/components/schemas/UserV2' - }, - 'type': 'array', - 'title': 'Response Get Users V2 V2 Users Get' - } - } + 'post': { + 'tags': [ + 'Users' + ], + 'summary': 'Create User V2', + 'operationId': 'create_user_v2_v2_users_post', + 'requestBody': { + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/UserV2' } } - } + }, + 'required': True }, - 'post': { - 'tags': [ - 'Users' - ], - 'summary': 'Create User V2', - 'operationId': 'create_user_v2_v2_users_post', - 'requestBody': { + 'responses': { + '200': { + 'description': 'Successful Response', 'content': { 'application/json': { 'schema': { '$ref': '#/components/schemas/UserV2' } } - }, - 'required': True + } }, - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/UserV2' - } - } - } - }, - '422': { - 'description': 'Validation Error', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/HTTPValidationError' - } + '422': { + 'description': 'Validation Error', + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/HTTPValidationError' } } } } } - }, - '/v2/users/{user_id}': { - 'get': { - 'tags': [ - 'Users' - ], - 'summary': 'Get User V2', - 'operationId': 'get_user_v2_v2_users__user_id__get', - 'parameters': [ - { - 'name': 'user_id', - 'in': 'path', - 'required': True, - 'schema': { - 'type': 'integer', - 'title': 'User Id' - } + } + }, + '/v2/users/{user_id}': { + 'get': { + 'tags': [ + 'Users' + ], + 'summary': 'Get User V2', + 'operationId': 'get_user_v2_v2_users__user_id__get', + 'parameters': [ + { + 'name': 'user_id', + 'in': 'path', + 'required': True, + 'schema': { + 'type': 'integer', + 'title': 'User Id' } - ], - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/UserV2' - } + } + ], + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/UserV2' } } - }, - '422': { - 'description': 'Validation Error', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/HTTPValidationError' - } + } + }, + '422': { + 'description': 'Validation Error', + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/HTTPValidationError' } } } } } - }, - '/latest/items': { - 'get': { - 'tags': [ - 'Items' - ], - 'summary': 'Get Items V2', - 'operationId': 'get_items_v2_latest_items_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'items': { - '$ref': '#/components/schemas/ItemV2' - }, - 'type': 'array', - 'title': 'Response Get Items V2 Latest Items Get' - } + } + }, + '/latest/items': { + 'get': { + 'tags': [ + 'Items' + ], + 'summary': 'Get Items V2', + 'operationId': 'get_items_v2_latest_items_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'items': { + '$ref': '#/components/schemas/ItemV2' + }, + 'type': 'array', + 'title': 'Response Get Items V2 Latest Items Get' } } } } + } + }, + 'post': { + 'tags': [ + 'Items' + ], + 'summary': 'Create Item V2', + 'operationId': 'create_item_v2_latest_items_post', + 'requestBody': { + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/ItemV2' + } + } + }, + 'required': True }, - 'post': { - 'tags': [ - 'Items' - ], - 'summary': 'Create Item V2', - 'operationId': 'create_item_v2_latest_items_post', - 'requestBody': { + 'responses': { + '200': { + 'description': 'Successful Response', 'content': { 'application/json': { 'schema': { '$ref': '#/components/schemas/ItemV2' } } - }, - 'required': True + } }, - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/ItemV2' - } + '422': { + 'description': 'Validation Error', + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/HTTPValidationError' } } - }, - '422': { - 'description': 'Validation Error', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/HTTPValidationError' - } + } + } + } + } + }, + '/latest/status': { + 'get': { + 'tags': [ + 'Status' + ], + 'summary': 'Get Status', + 'operationId': 'get_status_latest_status_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'type': 'string', + 'title': 'Response Get Status Latest Status Get' } } } } } - }, - '/latest/status': { - 'get': { - 'tags': [ - 'Status' - ], - 'summary': 'Get Status', - 'operationId': 'get_status_latest_status_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'type': 'string', - 'title': 'Response Get Status Latest Status Get' - } + } + }, + '/latest/users': { + 'get': { + 'tags': [ + 'Users' + ], + 'summary': 'Get Users V2', + 'operationId': 'get_users_v2_latest_users_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'items': { + '$ref': '#/components/schemas/UserV2' + }, + 'type': 'array', + 'title': 'Response Get Users V2 Latest Users Get' } } } } } }, - '/latest/users': { - 'get': { - 'tags': [ - 'Users' - ], - 'summary': 'Get Users V2', - 'operationId': 'get_users_v2_latest_users_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'items': { - '$ref': '#/components/schemas/UserV2' - }, - 'type': 'array', - 'title': 'Response Get Users V2 Latest Users Get' - } - } + 'post': { + 'tags': [ + 'Users' + ], + 'summary': 'Create User V2', + 'operationId': 'create_user_v2_latest_users_post', + 'requestBody': { + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/UserV2' } } - } + }, + 'required': True }, - 'post': { - 'tags': [ - 'Users' - ], - 'summary': 'Create User V2', - 'operationId': 'create_user_v2_latest_users_post', - 'requestBody': { + 'responses': { + '200': { + 'description': 'Successful Response', 'content': { 'application/json': { 'schema': { '$ref': '#/components/schemas/UserV2' } } - }, - 'required': True + } }, - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/UserV2' - } - } - } - }, - '422': { - 'description': 'Validation Error', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/HTTPValidationError' - } + '422': { + 'description': 'Validation Error', + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/HTTPValidationError' } } } } } - }, - '/latest/users/{user_id}': { - 'get': { - 'tags': [ - 'Users' - ], - 'summary': 'Get User V2', - 'operationId': 'get_user_v2_latest_users__user_id__get', - 'parameters': [ - { - 'name': 'user_id', - 'in': 'path', - 'required': True, - 'schema': { - 'type': 'integer', - 'title': 'User Id' - } + } + }, + '/latest/users/{user_id}': { + 'get': { + 'tags': [ + 'Users' + ], + 'summary': 'Get User V2', + 'operationId': 'get_user_v2_latest_users__user_id__get', + 'parameters': [ + { + 'name': 'user_id', + 'in': 'path', + 'required': True, + 'schema': { + 'type': 'integer', + 'title': 'User Id' } - ], - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/UserV2' - } + } + ], + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/UserV2' } } - }, - '422': { - 'description': 'Validation Error', - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/HTTPValidationError' - } + } + }, + '422': { + 'description': 'Validation Error', + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/HTTPValidationError' } } } } } - }, - '/versions': { - 'get': { - 'tags': [ - 'Versions' - ], - 'summary': 'Get Versions', - 'operationId': 'get_versions_versions_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'type': 'object', - 'title': 'Response Get Versions Versions Get' - } + } + }, + '/versions': { + 'get': { + 'tags': [ + 'Versions' + ], + 'summary': 'Get Versions', + 'operationId': 'get_versions_versions_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'type': 'object', + 'title': 'Response Get Versions Versions Get' } } } } } } - }, - 'components': { - 'schemas': { - 'HTTPValidationError': { - 'properties': { - 'detail': { - 'items': { - '$ref': '#/components/schemas/ValidationError' - }, - 'type': 'array', - 'title': 'Detail' - } - }, - 'type': 'object', - 'title': 'HTTPValidationError' - }, - 'Item': { - 'properties': { - 'id': { - 'type': 'integer', - 'title': 'Id' + } + }, + 'components': { + 'schemas': { + 'HTTPValidationError': { + 'properties': { + 'detail': { + 'items': { + '$ref': '#/components/schemas/ValidationError' }, - 'name': { - 'type': 'string', - 'title': 'Name' - } + 'type': 'array', + 'title': 'Detail' + } + }, + 'type': 'object', + 'title': 'HTTPValidationError' + }, + 'Item': { + 'properties': { + 'id': { + 'type': 'integer', + 'title': 'Id' }, - 'type': 'object', - 'required': [ - 'id', - 'name' - ], - 'title': 'Item' + 'name': { + 'type': 'string', + 'title': 'Name' + } }, - 'ItemV2': { - 'properties': { - 'id': { - 'type': 'integer', - 'title': 'Id' - }, - 'name': { - 'type': 'string', - 'title': 'Name' - }, - 'cost': { - 'type': 'integer', - 'title': 'Cost' - } + 'type': 'object', + 'required': [ + 'id', + 'name' + ], + 'title': 'Item' + }, + 'ItemV2': { + 'properties': { + 'id': { + 'type': 'integer', + 'title': 'Id' }, - 'type': 'object', - 'required': [ - 'id', - 'name', - 'cost' - ], - 'title': 'ItemV2' + 'name': { + 'type': 'string', + 'title': 'Name' + }, + 'cost': { + 'type': 'integer', + 'title': 'Cost' + } }, - 'User': { - 'properties': { - 'id': { - 'type': 'integer', - 'title': 'Id' - }, - 'name': { - 'type': 'string', - 'title': 'Name' - } + 'type': 'object', + 'required': [ + 'id', + 'name', + 'cost' + ], + 'title': 'ItemV2' + }, + 'User': { + 'properties': { + 'id': { + 'type': 'integer', + 'title': 'Id' }, - 'type': 'object', - 'required': [ - 'id', - 'name' - ], - 'title': 'User' + 'name': { + 'type': 'string', + 'title': 'Name' + } }, - 'UserV2': { - 'properties': { - 'id': { - 'type': 'integer', - 'title': 'Id' - }, - 'name': { - 'type': 'string', - 'title': 'Name' - }, - 'age': { - 'type': 'integer', - 'title': 'Age' - } + 'type': 'object', + 'required': [ + 'id', + 'name' + ], + 'title': 'User' + }, + 'UserV2': { + 'properties': { + 'id': { + 'type': 'integer', + 'title': 'Id' }, - 'type': 'object', - 'required': [ - 'id', - 'name', - 'age' - ], - 'title': 'UserV2' + 'name': { + 'type': 'string', + 'title': 'Name' + }, + 'age': { + 'type': 'integer', + 'title': 'Age' + } }, - 'ValidationError': { - 'properties': { - 'loc': { - 'items': { - 'anyOf': [ - { - 'type': 'string' - }, - { - 'type': 'integer' - } - ] - }, - 'type': 'array', - 'title': 'Location' - }, - 'msg': { - 'type': 'string', - 'title': 'Message' + 'type': 'object', + 'required': [ + 'id', + 'name', + 'age' + ], + 'title': 'UserV2' + }, + 'ValidationError': { + 'properties': { + 'loc': { + 'items': { + 'anyOf': [ + { + 'type': 'string' + }, + { + 'type': 'integer' + } + ] }, - 'type': { - 'type': 'string', - 'title': 'Error Type' - } + 'type': 'array', + 'title': 'Location' }, - 'type': 'object', - 'required': [ - 'loc', - 'msg', - 'type' - ], - 'title': 'ValidationError' - } + 'msg': { + 'type': 'string', + 'title': 'Message' + }, + 'type': { + 'type': 'string', + 'title': 'Error Type' + } + }, + 'type': 'object', + 'required': [ + 'loc', + 'msg', + 'type' + ], + 'title': 'ValidationError' } } } - if pydantic.__version__ >= "2.11.0": + } + if pydantic.__version__ >= '2.11.0': # added 'additionalProperties': True in the /versions API - expected_response["paths"]["/versions"]["get"]["responses"]["200"][ - "content" - ]["application/json"]["schema"]["additionalProperties"] = True + expected_response['paths']['/versions']['get']['responses']['200'][ + 'content' + ]['application/json']['schema']['additionalProperties'] = True # openapi self.assertDictEqual( expected_response, - test_client.get('/api_schema.json').json() + test_client.get('/api_schema.json').json() ) self.assertDictEqual( { diff --git a/tests/test_websocket.py b/tests/test_websocket.py index b248b0e..53adc6f 100644 --- a/tests/test_websocket.py +++ b/tests/test_websocket.py @@ -87,97 +87,96 @@ def test_simple_example(self) -> None: # openapi expected_response = { - 'openapi': '3.1.0', - 'info': { - 'title': 'test', - 'description': 'Websocket example of FastAPI Versionizer.', - 'termsOfService': 'https://github.com/alexschimpf/fastapi-versionizer', - 'version': '0.1.0' - }, - 'paths': { - '/v1/chatterbox': { - 'get': { - 'tags': [ - 'Chatting' - ], - 'summary': 'Get Explaination', - 'operationId': 'get_explaination_v1_chatterbox_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'type': 'string', - 'title': 'Response Get Explaination V1 Chatterbox Get' - } + 'openapi': '3.1.0', + 'info': { + 'title': 'test', + 'description': 'Websocket example of FastAPI Versionizer.', + 'termsOfService': 'https://github.com/alexschimpf/fastapi-versionizer', + 'version': '0.1.0' + }, + 'paths': { + '/v1/chatterbox': { + 'get': { + 'tags': [ + 'Chatting' + ], + 'summary': 'Get Explaination', + 'operationId': 'get_explaination_v1_chatterbox_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'type': 'string', + 'title': 'Response Get Explaination V1 Chatterbox Get' } } } - }, - 'deprecated': True - } - }, - '/v2/chatterbox': { - 'get': { - 'tags': [ - 'Chatting' - ], - 'summary': 'Get Explaination V2', - 'operationId': 'get_explaination_v2_v2_chatterbox_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'type': 'string', - 'title': 'Response Get Explaination V2 V2 Chatterbox Get' - } + } + }, + 'deprecated': True + } + }, + '/v2/chatterbox': { + 'get': { + 'tags': [ + 'Chatting' + ], + 'summary': 'Get Explaination V2', + 'operationId': 'get_explaination_v2_v2_chatterbox_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'type': 'string', + 'title': 'Response Get Explaination V2 V2 Chatterbox Get' } } } } } - }, - '/latest/chatterbox': { - 'get': { - 'tags': [ - 'Chatting' - ], - 'summary': 'Get Explaination V2', - 'operationId': 'get_explaination_v2_latest_chatterbox_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'type': 'string', - 'title': 'Response Get Explaination V2 Latest Chatterbox Get' - } + } + }, + '/latest/chatterbox': { + 'get': { + 'tags': [ + 'Chatting' + ], + 'summary': 'Get Explaination V2', + 'operationId': 'get_explaination_v2_latest_chatterbox_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'type': 'string', + 'title': 'Response Get Explaination V2 Latest Chatterbox Get' } } } } } - }, - '/versions': { - 'get': { - 'tags': [ - 'Versions' - ], - 'summary': 'Get Versions', - 'operationId': 'get_versions_versions_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'type': 'object', - 'title': 'Response Get Versions Versions Get' - } + } + }, + '/versions': { + 'get': { + 'tags': [ + 'Versions' + ], + 'summary': 'Get Versions', + 'operationId': 'get_versions_versions_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'type': 'object', + 'title': 'Response Get Versions Versions Get' } } } @@ -186,11 +185,12 @@ def test_simple_example(self) -> None: } } } - if pydantic.__version__ >= "2.11.0": + } + if pydantic.__version__ >= '2.11.0': # added 'additionalProperties': True in the /versions API - expected_response["paths"]["/versions"]["get"]["responses"]["200"][ - "content" - ]["application/json"]["schema"]["additionalProperties"] = True + expected_response['paths']['/versions']['get']['responses']['200'][ + 'content' + ]['application/json']['schema']['additionalProperties'] = True self.assertDictEqual( expected_response, test_client.get('/api_schema.json').json() diff --git a/tests/test_with_root_path.py b/tests/test_with_root_path.py index 9a3e577..8dcf832 100644 --- a/tests/test_with_root_path.py +++ b/tests/test_with_root_path.py @@ -46,99 +46,98 @@ def test_with_root_path_example(self) -> None: # openapi expected_response = { - 'openapi': '3.1.0', - 'info': { - 'title': 'test', - 'version': '0.1.0' - }, - 'servers': [ - { - 'url': '/api' - } - ], - 'paths': { - '/v1/status': { - 'get': { - 'tags': [ - 'Status' - ], - 'summary': 'Get Status V1', - 'operationId': 'get_status_v1_v1_status_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'type': 'string', - 'title': 'Response Get Status V1 V1 Status Get' - } + 'openapi': '3.1.0', + 'info': { + 'title': 'test', + 'version': '0.1.0' + }, + 'servers': [ + { + 'url': '/api' + } + ], + 'paths': { + '/v1/status': { + 'get': { + 'tags': [ + 'Status' + ], + 'summary': 'Get Status V1', + 'operationId': 'get_status_v1_v1_status_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'type': 'string', + 'title': 'Response Get Status V1 V1 Status Get' } } } } } - }, - '/v2/status': { - 'get': { - 'tags': [ - 'Status' - ], - 'summary': 'Get Status V2', - 'operationId': 'get_status_v2_v2_status_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'type': 'string', - 'title': 'Response Get Status V2 V2 Status Get' - } + } + }, + '/v2/status': { + 'get': { + 'tags': [ + 'Status' + ], + 'summary': 'Get Status V2', + 'operationId': 'get_status_v2_v2_status_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'type': 'string', + 'title': 'Response Get Status V2 V2 Status Get' } } } } } - }, - '/latest/status': { - 'get': { - 'tags': [ - 'Status' - ], - 'summary': 'Get Status V2', - 'operationId': 'get_status_v2_latest_status_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'type': 'string', - 'title': 'Response Get Status V2 Latest Status Get' - } + } + }, + '/latest/status': { + 'get': { + 'tags': [ + 'Status' + ], + 'summary': 'Get Status V2', + 'operationId': 'get_status_v2_latest_status_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'type': 'string', + 'title': 'Response Get Status V2 Latest Status Get' } } } } } - }, - '/versions': { - 'get': { - 'tags': [ - 'Versions' - ], - 'summary': 'Get Versions', - 'operationId': 'get_versions_versions_get', - 'responses': { - '200': { - 'description': 'Successful Response', - 'content': { - 'application/json': { - 'schema': { - 'type': 'object', - 'title': 'Response Get Versions Versions Get' - } + } + }, + '/versions': { + 'get': { + 'tags': [ + 'Versions' + ], + 'summary': 'Get Versions', + 'operationId': 'get_versions_versions_get', + 'responses': { + '200': { + 'description': 'Successful Response', + 'content': { + 'application/json': { + 'schema': { + 'type': 'object', + 'title': 'Response Get Versions Versions Get' } } } @@ -147,11 +146,12 @@ def test_with_root_path_example(self) -> None: } } } - if pydantic.__version__ >= "2.11.0": + } + if pydantic.__version__ >= '2.11.0': # added 'additionalProperties': True in the /versions API - expected_response["paths"]["/versions"]["get"]["responses"]["200"][ - "content" - ]["application/json"]["schema"]["additionalProperties"] = True + expected_response['paths']['/versions']['get']['responses']['200'][ + 'content' + ]['application/json']['schema']['additionalProperties'] = True self.assertDictEqual( expected_response, test_client.get('/api/api_schema.json').json() From 5af4be5af1c6a62e8b407691b8a97dfe435b7055 Mon Sep 17 00:00:00 2001 From: OlegZv <19969581+OlegZv@users.noreply.github.com> Date: Sun, 1 Jun 2025 01:45:28 -0400 Subject: [PATCH 5/7] chore: Fix typing errors --- tests/test_simple.py | 3 ++- tests/test_websocket.py | 3 ++- tests/test_with_root_path.py | 3 ++- tests/test_with_static_file_mount.py | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/test_simple.py b/tests/test_simple.py index 9b8f0ae..2b6785a 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -1,3 +1,4 @@ +from typing import Any, Dict from fastapi.testclient import TestClient from unittest import TestCase @@ -136,7 +137,7 @@ def test_simple_example(self) -> None: self.assertEqual(200, test_client.get('/v1/swagger').status_code) self.assertEqual(200, test_client.get('/v2/swagger').status_code) self.assertEqual(200, test_client.get('/latest/swagger').status_code) - expected_response = { + expected_response: Dict[str, Any] = { 'openapi': '3.1.0', 'info': { 'title': 'test', diff --git a/tests/test_websocket.py b/tests/test_websocket.py index 53adc6f..43094e7 100644 --- a/tests/test_websocket.py +++ b/tests/test_websocket.py @@ -1,3 +1,4 @@ +from typing import Any, Dict import pydantic from fastapi import WebSocketDisconnect from fastapi.testclient import TestClient @@ -86,7 +87,7 @@ def test_simple_example(self) -> None: self.assertEqual(200, test_client.get('/latest/swagger').status_code) # openapi - expected_response = { + expected_response: Dict[str, Any] = { 'openapi': '3.1.0', 'info': { 'title': 'test', diff --git a/tests/test_with_root_path.py b/tests/test_with_root_path.py index 8dcf832..3a440c3 100644 --- a/tests/test_with_root_path.py +++ b/tests/test_with_root_path.py @@ -1,3 +1,4 @@ +from typing import Any, Dict import pydantic from fastapi.testclient import TestClient @@ -45,7 +46,7 @@ def test_with_root_path_example(self) -> None: self.assertEqual(200, test_client.get('/latest/swagger').status_code) # openapi - expected_response = { + expected_response: Dict[str, Any] = { 'openapi': '3.1.0', 'info': { 'title': 'test', diff --git a/tests/test_with_static_file_mount.py b/tests/test_with_static_file_mount.py index 859f0fa..1578967 100644 --- a/tests/test_with_static_file_mount.py +++ b/tests/test_with_static_file_mount.py @@ -17,5 +17,5 @@ def test_with_static_file_mount_example(self) -> None: self.assertEqual(expected, test_client.get('/examples/with_static_file_mount.py').text) # Check that a static mount before instantiating Versionizer will not work - self.assertEquals('{"detail":"Not Found"}', + self.assertEqual('{"detail":"Not Found"}', test_client.get('/examples-not-working/with_static_file_mount.py').text) From 70096ef78c56fd3918f0cf795442e6fd681c0106 Mon Sep 17 00:00:00 2001 From: OlegZv <19969581+OlegZv@users.noreply.github.com> Date: Sun, 1 Jun 2025 01:49:21 -0400 Subject: [PATCH 6/7] chore: Linter fix --- tests/test_with_static_file_mount.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_with_static_file_mount.py b/tests/test_with_static_file_mount.py index 1578967..d807cfb 100644 --- a/tests/test_with_static_file_mount.py +++ b/tests/test_with_static_file_mount.py @@ -18,4 +18,4 @@ def test_with_static_file_mount_example(self) -> None: # Check that a static mount before instantiating Versionizer will not work self.assertEqual('{"detail":"Not Found"}', - test_client.get('/examples-not-working/with_static_file_mount.py').text) + test_client.get('/examples-not-working/with_static_file_mount.py').text) From 23baecdd8d77a5fb57b82a581f87f04f255964e8 Mon Sep 17 00:00:00 2001 From: OlegZv <19969581+OlegZv@users.noreply.github.com> Date: Tue, 3 Jun 2025 22:16:45 -0400 Subject: [PATCH 7/7] chore: Add test pypi deployment --- .github/workflows/deploy.yml | 31 ++++++++++++++++++++++++++++++- .github/workflows/release.yml | 2 +- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 7364d62..60b05a7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -6,8 +6,37 @@ on: - published jobs: - deploy: + publish-to-test-pypi: runs-on: ubuntu-latest + environment: + name: test + permissions: + id-token: write + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.8' + + - name: Build the distribution + run: make build + - name: Install the package + run: make test-install-build + - name: Publish package distributions to Test PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ + + publish-to-pypi: + runs-on: ubuntu-latest + environment: + name: production + # if release to test PyPI fails, still run this job + # since we can check the reason for failure manually + # before approving the release + if: always() + needs: publish-to-test-pypi permissions: id-token: write diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d589497..30a2d35 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,4 +19,4 @@ jobs: - name: Generate a release env: GITHUB_TOKEN: ${{ secrets.CLI_PAT }} - run: pnpm run release \ No newline at end of file + run: pnpm run release