fastapi-breakgate 1.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. fastapi_breakgate-1.0.1/.gitignore +19 -0
  2. fastapi_breakgate-1.0.1/CHANGELOG.md +28 -0
  3. fastapi_breakgate-1.0.1/LICENSE +21 -0
  4. fastapi_breakgate-1.0.1/PKG-INFO +191 -0
  5. fastapi_breakgate-1.0.1/README.md +145 -0
  6. fastapi_breakgate-1.0.1/action/action.yml +118 -0
  7. fastapi_breakgate-1.0.1/examples/demo_app/__init__.py +1 -0
  8. fastapi_breakgate-1.0.1/examples/demo_app/main.py +47 -0
  9. fastapi_breakgate-1.0.1/examples/demo_app/openapi.snapshot.json +224 -0
  10. fastapi_breakgate-1.0.1/examples/demo_app/pyproject.toml +10 -0
  11. fastapi_breakgate-1.0.1/pyproject.toml +139 -0
  12. fastapi_breakgate-1.0.1/src/fastapi_contract/__init__.py +26 -0
  13. fastapi_breakgate-1.0.1/src/fastapi_contract/__main__.py +4 -0
  14. fastapi_breakgate-1.0.1/src/fastapi_contract/__version__.py +1 -0
  15. fastapi_breakgate-1.0.1/src/fastapi_contract/check.py +167 -0
  16. fastapi_breakgate-1.0.1/src/fastapi_contract/cli.py +295 -0
  17. fastapi_breakgate-1.0.1/src/fastapi_contract/comment.py +101 -0
  18. fastapi_breakgate-1.0.1/src/fastapi_contract/config.py +161 -0
  19. fastapi_breakgate-1.0.1/src/fastapi_contract/diff/__init__.py +5 -0
  20. fastapi_breakgate-1.0.1/src/fastapi_contract/diff/classifier.py +779 -0
  21. fastapi_breakgate-1.0.1/src/fastapi_contract/diff/oasdiff.py +160 -0
  22. fastapi_breakgate-1.0.1/src/fastapi_contract/diff/policy.py +85 -0
  23. fastapi_breakgate-1.0.1/src/fastapi_contract/doctor.py +251 -0
  24. fastapi_breakgate-1.0.1/src/fastapi_contract/export.py +283 -0
  25. fastapi_breakgate-1.0.1/src/fastapi_contract/intentional.py +109 -0
  26. fastapi_breakgate-1.0.1/src/fastapi_contract/models.py +33 -0
  27. fastapi_breakgate-1.0.1/src/fastapi_contract/py.typed +0 -0
  28. fastapi_breakgate-1.0.1/src/fastapi_contract/pytest_plugin.py +98 -0
  29. fastapi_breakgate-1.0.1/tests/conftest.py +115 -0
  30. fastapi_breakgate-1.0.1/tests/test_check_intentional_cli.py +160 -0
  31. fastapi_breakgate-1.0.1/tests/test_comment_oasdiff_config.py +163 -0
  32. fastapi_breakgate-1.0.1/tests/test_diff_classifier.py +172 -0
  33. fastapi_breakgate-1.0.1/tests/test_export_and_doctor.py +102 -0
  34. fastapi_breakgate-1.0.1/tests/test_integration_e2e.py +341 -0
  35. fastapi_breakgate-1.0.1/tests/test_more_coverage.py +283 -0
  36. fastapi_breakgate-1.0.1/tests/test_pytest_plugin.py +24 -0
@@ -0,0 +1,19 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .eggs/
5
+ dist/
6
+ build/
7
+ .pytest_cache/
8
+ .mypy_cache/
9
+ .ruff_cache/
10
+ .coverage
11
+ htmlcov/
12
+ .venv/
13
+ venv/
14
+ .env
15
+ *.snapshot.json.bak
16
+ contract-report.md
17
+ contract-comment.md
18
+ openapi.json
19
+ .DS_Store
@@ -0,0 +1,28 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## 1.0.1 — 2026-11-15
6
+
7
+ ### Changed
8
+
9
+ - PyPI distribution name is **`fastapi-breakgate`** (`fastapi-contract` was already taken on PyPI)
10
+ - CLI entry points: `fastapi-breakgate` (primary) and `fastapi-contract` (alias)
11
+ - GitHub repo: `prakash888kp/fastapi-breakgate`
12
+
13
+ ### Fixed
14
+
15
+ - Resolve nested OpenAPI `$ref` enums (FastAPI component schemas) during property comparison
16
+ - Diff component-level enum add/remove so policy (`additive-friendly` vs `strict`) applies correctly
17
+ - Expanded integration E2E coverage for additive/breaking/intentional/CLI/pytest-plugin flows
18
+
19
+ ## 1.0.0 — 2026-11-15
20
+
21
+ ### Added
22
+
23
+ - Production-ready `fastapi-contract` package with CLI, pytest plugin, and GitHub Action
24
+ - Reliable OpenAPI export ladder (live / factory / snapshot) with `doctor`
25
+ - Pure-Python OpenAPI breaking-change classifier with `additive-friendly` and `strict` policies
26
+ - Optional oasdiff integration when the binary is available
27
+ - Intentional breaking-change protocol (label/title marker + changelog section)
28
+ - PR markdown reports, SemVer bump hints, and GitHub Actions annotations
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 prakash888kp / fastapi-breakgate contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,191 @@
1
+ Metadata-Version: 2.5
2
+ Name: fastapi-breakgate
3
+ Version: 1.0.1
4
+ Summary: Production merge gate for FastAPI: export live OpenAPI, detect breaking changes, enforce intentional-break protocol.
5
+ Project-URL: Homepage, https://github.com/prakash888kp/fastapi-breakgate
6
+ Project-URL: Documentation, https://github.com/prakash888kp/fastapi-breakgate#readme
7
+ Project-URL: Repository, https://github.com/prakash888kp/fastapi-breakgate
8
+ Project-URL: Issues, https://github.com/prakash888kp/fastapi-breakgate/issues
9
+ Project-URL: Changelog, https://github.com/prakash888kp/fastapi-breakgate/blob/main/CHANGELOG.md
10
+ Author-email: prakash888kp <prakash888kp@users.noreply.github.com>
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: api-compatibility,breaking-changes,ci,contract-testing,fastapi,openapi
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Environment :: Console
16
+ Classifier: Framework :: FastAPI
17
+ Classifier: Framework :: Pytest
18
+ Classifier: Intended Audience :: Developers
19
+ Classifier: License :: OSI Approved :: MIT License
20
+ Classifier: Operating System :: OS Independent
21
+ Classifier: Programming Language :: Python :: 3
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Programming Language :: Python :: 3.13
26
+ Classifier: Programming Language :: Python :: 3.14
27
+ Classifier: Topic :: Software Development :: Quality Assurance
28
+ Classifier: Topic :: Software Development :: Testing
29
+ Classifier: Typing :: Typed
30
+ Requires-Python: >=3.10
31
+ Requires-Dist: fastapi>=0.110
32
+ Requires-Dist: rich>=13.7
33
+ Requires-Dist: tomli>=2.0.1; python_version < '3.11'
34
+ Requires-Dist: typer>=0.12
35
+ Requires-Dist: typing-extensions>=4.8; python_version < '3.11'
36
+ Provides-Extra: dev
37
+ Requires-Dist: build>=1.2; extra == 'dev'
38
+ Requires-Dist: httpx>=0.27; extra == 'dev'
39
+ Requires-Dist: mypy>=1.11; extra == 'dev'
40
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
41
+ Requires-Dist: pytest>=8.0; extra == 'dev'
42
+ Requires-Dist: ruff>=0.6; extra == 'dev'
43
+ Requires-Dist: twine>=5.0; extra == 'dev'
44
+ Provides-Extra: oasdiff
45
+ Description-Content-Type: text/markdown
46
+
47
+ # fastapi-breakgate
48
+
49
+ **Production merge gate for FastAPI.** Export live OpenAPI in CI, fail on accidental breaking changes, and make intentional breaks an explicit, changelog-backed review event.
50
+
51
+ > Status: **Beta (v1.0.1)** — core gate is solid; dogfood on real apps welcome.
52
+ > Not a fuzzer (that’s Schemathesis). Not a visual OpenAPI browser. A **hard merge gate** with FastAPI-aware DX.
53
+
54
+ > **Note:** The PyPI name is `fastapi-breakgate` because `fastapi-contract` is already taken by an unrelated project. The import package remains `fastapi_contract`.
55
+
56
+ ## Install
57
+
58
+ ```bash
59
+ pip install fastapi-breakgate
60
+ ```
61
+
62
+ CLI commands (either entry point works):
63
+
64
+ ```bash
65
+ fastapi-breakgate --help
66
+ fastapi-contract --help
67
+ ```
68
+
69
+ ## 5-minute setup
70
+
71
+ ### 1. Configure
72
+
73
+ ```toml
74
+ # pyproject.toml
75
+ [tool.fastapi_contract]
76
+ app = "myapp.main:app"
77
+ policy = "additive-friendly" # or "strict"
78
+ fail_on = "breaking"
79
+ snapshot_path = "openapi.snapshot.json"
80
+ intentional_label = "breaking-change"
81
+ intentional_title_marker = "[breaking-change]"
82
+ changelog_required_heading = "### Breaking"
83
+ ```
84
+
85
+ ### 2. Commit a base snapshot
86
+
87
+ ```bash
88
+ fastapi-breakgate doctor --app myapp.main:app
89
+ fastapi-breakgate snapshot --app myapp.main:app
90
+ git add openapi.snapshot.json && git commit -m "chore: add OpenAPI contract snapshot"
91
+ ```
92
+
93
+ ### 3. Gate PRs (GitHub Action)
94
+
95
+ ```yaml
96
+ # .github/workflows/contract.yml
97
+ name: API contract
98
+ on:
99
+ pull_request:
100
+ jobs:
101
+ contract:
102
+ runs-on: ubuntu-latest
103
+ steps:
104
+ - uses: actions/checkout@v4
105
+ - uses: actions/setup-python@v5
106
+ with:
107
+ python-version: "3.12"
108
+ - name: Install project
109
+ run: pip install -e ".[dev]"
110
+ - uses: prakash888kp/fastapi-breakgate/action@v1
111
+ with:
112
+ app: myapp.main:app
113
+ fail-on: breaking
114
+ policy: additive-friendly
115
+ install-command: ""
116
+ ```
117
+
118
+ Or call the CLI directly:
119
+
120
+ ```bash
121
+ pip install fastapi-breakgate
122
+ fastapi-breakgate check --app myapp.main:app --annotations
123
+ ```
124
+
125
+ ## CLI
126
+
127
+ | Command | Purpose |
128
+ |---------|---------|
129
+ | `fastapi-breakgate doctor` | Diagnose import/export readiness |
130
+ | `fastapi-breakgate export -o openapi.json` | Export live OpenAPI |
131
+ | `fastapi-breakgate snapshot` | Write committed snapshot |
132
+ | `fastapi-breakgate diff --base-file openapi.snapshot.json` | Classify changes |
133
+ | `fastapi-breakgate check` | CI entrypoint (exit 1 on accidental breaks) |
134
+ | `fastapi-breakgate comment -o pr.md` | Render PR markdown |
135
+
136
+ ## Intentional breaking changes
137
+
138
+ Accidental breaks fail CI. Planned breaks must complete the protocol:
139
+
140
+ 1. PR label `breaking-change` **or** title contains `[breaking-change]`
141
+ 2. `CHANGELOG.md` includes `### Breaking` with at least one bullet
142
+
143
+ Then the check passes with a visible warning and SemVer **major** suggestion.
144
+
145
+ ## Pytest plugin
146
+
147
+ ```python
148
+ def test_openapi_contract(fastapi_contract):
149
+ fastapi_contract.assert_compatible()
150
+ ```
151
+
152
+ ```bash
153
+ pytest --fastapi-contract-app=myapp.main:app --fastapi-contract-base=openapi.snapshot.json
154
+ ```
155
+
156
+ ## Policy
157
+
158
+ | Change | `additive-friendly` (default) | `strict` |
159
+ |--------|-------------------------------|----------|
160
+ | Add optional response field | safe | safe |
161
+ | Add response enum value | **safe** | breaking |
162
+ | Remove path / field | breaking | breaking |
163
+ | Add required request field | breaking | breaking |
164
+
165
+ ## Export reliability
166
+
167
+ Real apps often need DB/env at import time. Strategy ladder:
168
+
169
+ 1. **Live** import with stub/default env + optional `.env.contract`
170
+ 2. **Factory** (`create_app()`) when configured/detected
171
+ 3. **Snapshot** fallback in `export_mode = "auto"` with an explicit warning
172
+
173
+ Run `fastapi-breakgate doctor` when CI import fails.
174
+
175
+ ## Development
176
+
177
+ ```bash
178
+ pip install -e ".[dev]"
179
+ export PYTHONPATH=src:examples
180
+ python -m coverage run -m pytest
181
+ python -m coverage report --fail-under=75
182
+ ruff check src tests
183
+ ```
184
+
185
+ ## Release / PyPI
186
+
187
+ Tagging `vX.Y.Z` (must match `pyproject.toml`) runs CI tests, publishes to PyPI via Trusted Publishing, and creates a GitHub Release.
188
+
189
+ ## License
190
+
191
+ MIT
@@ -0,0 +1,145 @@
1
+ # fastapi-breakgate
2
+
3
+ **Production merge gate for FastAPI.** Export live OpenAPI in CI, fail on accidental breaking changes, and make intentional breaks an explicit, changelog-backed review event.
4
+
5
+ > Status: **Beta (v1.0.1)** — core gate is solid; dogfood on real apps welcome.
6
+ > Not a fuzzer (that’s Schemathesis). Not a visual OpenAPI browser. A **hard merge gate** with FastAPI-aware DX.
7
+
8
+ > **Note:** The PyPI name is `fastapi-breakgate` because `fastapi-contract` is already taken by an unrelated project. The import package remains `fastapi_contract`.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ pip install fastapi-breakgate
14
+ ```
15
+
16
+ CLI commands (either entry point works):
17
+
18
+ ```bash
19
+ fastapi-breakgate --help
20
+ fastapi-contract --help
21
+ ```
22
+
23
+ ## 5-minute setup
24
+
25
+ ### 1. Configure
26
+
27
+ ```toml
28
+ # pyproject.toml
29
+ [tool.fastapi_contract]
30
+ app = "myapp.main:app"
31
+ policy = "additive-friendly" # or "strict"
32
+ fail_on = "breaking"
33
+ snapshot_path = "openapi.snapshot.json"
34
+ intentional_label = "breaking-change"
35
+ intentional_title_marker = "[breaking-change]"
36
+ changelog_required_heading = "### Breaking"
37
+ ```
38
+
39
+ ### 2. Commit a base snapshot
40
+
41
+ ```bash
42
+ fastapi-breakgate doctor --app myapp.main:app
43
+ fastapi-breakgate snapshot --app myapp.main:app
44
+ git add openapi.snapshot.json && git commit -m "chore: add OpenAPI contract snapshot"
45
+ ```
46
+
47
+ ### 3. Gate PRs (GitHub Action)
48
+
49
+ ```yaml
50
+ # .github/workflows/contract.yml
51
+ name: API contract
52
+ on:
53
+ pull_request:
54
+ jobs:
55
+ contract:
56
+ runs-on: ubuntu-latest
57
+ steps:
58
+ - uses: actions/checkout@v4
59
+ - uses: actions/setup-python@v5
60
+ with:
61
+ python-version: "3.12"
62
+ - name: Install project
63
+ run: pip install -e ".[dev]"
64
+ - uses: prakash888kp/fastapi-breakgate/action@v1
65
+ with:
66
+ app: myapp.main:app
67
+ fail-on: breaking
68
+ policy: additive-friendly
69
+ install-command: ""
70
+ ```
71
+
72
+ Or call the CLI directly:
73
+
74
+ ```bash
75
+ pip install fastapi-breakgate
76
+ fastapi-breakgate check --app myapp.main:app --annotations
77
+ ```
78
+
79
+ ## CLI
80
+
81
+ | Command | Purpose |
82
+ |---------|---------|
83
+ | `fastapi-breakgate doctor` | Diagnose import/export readiness |
84
+ | `fastapi-breakgate export -o openapi.json` | Export live OpenAPI |
85
+ | `fastapi-breakgate snapshot` | Write committed snapshot |
86
+ | `fastapi-breakgate diff --base-file openapi.snapshot.json` | Classify changes |
87
+ | `fastapi-breakgate check` | CI entrypoint (exit 1 on accidental breaks) |
88
+ | `fastapi-breakgate comment -o pr.md` | Render PR markdown |
89
+
90
+ ## Intentional breaking changes
91
+
92
+ Accidental breaks fail CI. Planned breaks must complete the protocol:
93
+
94
+ 1. PR label `breaking-change` **or** title contains `[breaking-change]`
95
+ 2. `CHANGELOG.md` includes `### Breaking` with at least one bullet
96
+
97
+ Then the check passes with a visible warning and SemVer **major** suggestion.
98
+
99
+ ## Pytest plugin
100
+
101
+ ```python
102
+ def test_openapi_contract(fastapi_contract):
103
+ fastapi_contract.assert_compatible()
104
+ ```
105
+
106
+ ```bash
107
+ pytest --fastapi-contract-app=myapp.main:app --fastapi-contract-base=openapi.snapshot.json
108
+ ```
109
+
110
+ ## Policy
111
+
112
+ | Change | `additive-friendly` (default) | `strict` |
113
+ |--------|-------------------------------|----------|
114
+ | Add optional response field | safe | safe |
115
+ | Add response enum value | **safe** | breaking |
116
+ | Remove path / field | breaking | breaking |
117
+ | Add required request field | breaking | breaking |
118
+
119
+ ## Export reliability
120
+
121
+ Real apps often need DB/env at import time. Strategy ladder:
122
+
123
+ 1. **Live** import with stub/default env + optional `.env.contract`
124
+ 2. **Factory** (`create_app()`) when configured/detected
125
+ 3. **Snapshot** fallback in `export_mode = "auto"` with an explicit warning
126
+
127
+ Run `fastapi-breakgate doctor` when CI import fails.
128
+
129
+ ## Development
130
+
131
+ ```bash
132
+ pip install -e ".[dev]"
133
+ export PYTHONPATH=src:examples
134
+ python -m coverage run -m pytest
135
+ python -m coverage report --fail-under=75
136
+ ruff check src tests
137
+ ```
138
+
139
+ ## Release / PyPI
140
+
141
+ Tagging `vX.Y.Z` (must match `pyproject.toml`) runs CI tests, publishes to PyPI via Trusted Publishing, and creates a GitHub Release.
142
+
143
+ ## License
144
+
145
+ MIT
@@ -0,0 +1,118 @@
1
+ name: fastapi-breakgate
2
+ description: Fail PRs on accidental FastAPI OpenAPI breaking changes.
3
+ author: prakash888kp
4
+ branding:
5
+ icon: shield
6
+ color: green
7
+
8
+ inputs:
9
+ app:
10
+ description: FastAPI target as module:attr (e.g. myapp.main:app)
11
+ required: true
12
+ fail-on:
13
+ description: breaking | risky | any
14
+ required: false
15
+ default: breaking
16
+ policy:
17
+ description: additive-friendly | strict
18
+ required: false
19
+ default: additive-friendly
20
+ base-file:
21
+ description: Path to base OpenAPI JSON (defaults to openapi.snapshot.json)
22
+ required: false
23
+ default: ""
24
+ working-directory:
25
+ description: Directory containing the FastAPI project
26
+ required: false
27
+ default: "."
28
+ python-version:
29
+ description: Python version for the runner setup (informational; use setup-python before)
30
+ required: false
31
+ default: "3.12"
32
+ install-command:
33
+ description: Command to install project dependencies before the check
34
+ required: false
35
+ default: "pip install -e ."
36
+ pr-title:
37
+ description: Override PR title for intentional protocol (defaults to github.event.pull_request.title)
38
+ required: false
39
+ default: ""
40
+ pr-labels:
41
+ description: Comma-separated labels (defaults to PR labels)
42
+ required: false
43
+ default: ""
44
+ report-path:
45
+ description: Where to write the markdown report
46
+ required: false
47
+ default: contract-report.md
48
+
49
+ outputs:
50
+ report-path:
51
+ description: Path to the generated markdown report
52
+ value: ${{ inputs.report-path }}
53
+ conclusion:
54
+ description: success or failure
55
+ value: ${{ steps.check.outputs.conclusion }}
56
+
57
+ runs:
58
+ using: composite
59
+ steps:
60
+ - name: Install fastapi-breakgate
61
+ shell: bash
62
+ working-directory: ${{ inputs.working-directory }}
63
+ run: |
64
+ python -m pip install --upgrade pip
65
+ python -m pip install "fastapi-breakgate>=1.0.1"
66
+ if [ -n "${{ inputs.install-command }}" ]; then
67
+ ${{ inputs.install-command }}
68
+ fi
69
+
70
+ - name: Resolve PR metadata
71
+ id: meta
72
+ shell: bash
73
+ run: |
74
+ TITLE="${{ inputs.pr-title }}"
75
+ if [ -z "$TITLE" ]; then
76
+ TITLE="${{ github.event.pull_request.title }}"
77
+ fi
78
+ LABELS="${{ inputs.pr-labels }}"
79
+ if [ -z "$LABELS" ]; then
80
+ LABELS=$(python - <<'PY'
81
+ import json, os
82
+ event_path = os.environ.get("GITHUB_EVENT_PATH")
83
+ labels = []
84
+ if event_path and os.path.isfile(event_path):
85
+ with open(event_path, encoding="utf-8") as f:
86
+ event = json.load(f)
87
+ for label in event.get("pull_request", {}).get("labels", []) or []:
88
+ name = label.get("name")
89
+ if name:
90
+ labels.append(name)
91
+ print(",".join(labels))
92
+ PY
93
+ )
94
+ fi
95
+ echo "title=$TITLE" >> "$GITHUB_OUTPUT"
96
+ echo "labels=$LABELS" >> "$GITHUB_OUTPUT"
97
+
98
+ - name: Run contract check
99
+ id: check
100
+ shell: bash
101
+ working-directory: ${{ inputs.working-directory }}
102
+ env:
103
+ FAC_PR_TITLE: ${{ steps.meta.outputs.title }}
104
+ FAC_PR_LABELS: ${{ steps.meta.outputs.labels }}
105
+ run: |
106
+ set +e
107
+ ARGS=(check --app "${{ inputs.app }}" --fail-on "${{ inputs.fail-on }}" --policy "${{ inputs.policy }}" --report "${{ inputs.report-path }}" --annotations)
108
+ if [ -n "${{ inputs.base-file }}" ]; then
109
+ ARGS+=(--base-file "${{ inputs.base-file }}")
110
+ fi
111
+ fastapi-breakgate "${ARGS[@]}"
112
+ CODE=$?
113
+ if [ "$CODE" -eq 0 ]; then
114
+ echo "conclusion=success" >> "$GITHUB_OUTPUT"
115
+ else
116
+ echo "conclusion=failure" >> "$GITHUB_OUTPUT"
117
+ fi
118
+ exit "$CODE"
@@ -0,0 +1 @@
1
+ """Demo FastAPI application used in docs and local smoke tests."""
@@ -0,0 +1,47 @@
1
+ """Minimal FastAPI app demonstrating fastapi-contract."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from enum import Enum
6
+ from typing import Optional
7
+
8
+ from fastapi import FastAPI
9
+ from pydantic import BaseModel, Field
10
+
11
+
12
+ class Status(str, Enum):
13
+ ACTIVE = "active"
14
+ INACTIVE = "inactive"
15
+
16
+
17
+ class ItemCreate(BaseModel):
18
+ name: str = Field(..., min_length=1)
19
+ status: Status = Status.ACTIVE
20
+ note: Optional[str] = None
21
+
22
+
23
+ class Item(BaseModel):
24
+ id: int
25
+ name: str
26
+ status: Status
27
+
28
+
29
+ def create_app() -> FastAPI:
30
+ app = FastAPI(title="Demo API", version="1.0.0")
31
+
32
+ @app.get("/health")
33
+ def health() -> dict[str, str]:
34
+ return {"status": "ok"}
35
+
36
+ @app.get("/items/{item_id}", response_model=Item)
37
+ def get_item(item_id: int) -> Item:
38
+ return Item(id=item_id, name="demo", status=Status.ACTIVE)
39
+
40
+ @app.post("/items", response_model=Item, status_code=201)
41
+ def create_item(payload: ItemCreate) -> Item:
42
+ return Item(id=1, name=payload.name, status=payload.status)
43
+
44
+ return app
45
+
46
+
47
+ app = create_app()