Skip to content

Commit aff6335

Browse files
nanotaboadaclaude
andcommitted
ci(cd): verify tag commit is reachable from master (#549)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent f0a4a5d commit aff6335

File tree

4 files changed

+43
-11
lines changed

4 files changed

+43
-11
lines changed

.github/workflows/python-cd.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ jobs:
2424
with:
2525
fetch-depth: 0
2626

27+
- name: Verify tag commit is reachable from master
28+
run: |
29+
if ! git merge-base --is-ancestor ${{ github.sha }} origin/master; then
30+
echo "Error: Tag commit ${{ github.sha }} is not reachable from master."
31+
echo "Tags must only be created from master after the release PR is merged."
32+
exit 1
33+
fi
34+
echo "Verified: tag commit ${{ github.sha }} is reachable from master."
35+
2736
- name: Extract version from tag
2837
id: version
2938
run: |

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ This project uses famous football coaches as release codenames, following an A-Z
4444

4545
### Added
4646

47+
- CD workflow now verifies tag commit is reachable from `master` before
48+
proceeding with build and publish steps (#549)
49+
4750
### Changed
4851

4952
- `GET /players/` cache check changed from `if not players` to

tests/conftest.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import pytest
33
from fastapi.testclient import TestClient
44
from main import app
5+
from tests.player_stub import nonexistent_player
56

67
# Suppress the DeprecationWarning from httpx
78
warnings.filterwarnings("ignore", category=DeprecationWarning)
@@ -20,3 +21,17 @@ def client():
2021
"""
2122
with TestClient(app) as test_client:
2223
yield test_client
24+
25+
26+
@pytest.fixture(scope="function")
27+
def nonexistent_player_in_db(client):
28+
"""
29+
Creates the nonexistent player in the database and removes it on teardown.
30+
31+
Yields:
32+
Player: The player stub created in the database.
33+
"""
34+
player = nonexistent_player()
35+
client.post("/players/", json=player.__dict__)
36+
yield player
37+
client.delete(f"/players/squadnumber/{player.squad_number}")

tests/test_main.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -194,13 +194,17 @@ def test_request_post_player_body_nonexistent_response_status_created(client):
194194
"""POST /players/ with nonexistent player returns 201 Created with a valid UUID"""
195195
# Arrange
196196
player = nonexistent_player()
197-
# Act
198-
response = client.post(PATH, json=player.__dict__)
199-
# Assert
200-
assert response.status_code == 201
201-
body = response.json()
202-
assert "id" in body
203-
assert UUID(body["id"]).version == 4 # UUID v4 (API-created)
197+
try:
198+
# Act
199+
response = client.post(PATH, json=player.__dict__)
200+
# Assert
201+
assert response.status_code == 201
202+
body = response.json()
203+
assert "id" in body
204+
assert UUID(body["id"]).version == 4 # UUID v4 (API-created)
205+
finally:
206+
# Teardown — remove the created player
207+
client.delete(PATH + "squadnumber/" + str(player.squad_number))
204208

205209

206210
# PUT /players/squadnumber/{squad_number} --------------------------------------
@@ -278,11 +282,12 @@ def test_request_delete_player_squadnumber_unknown_response_status_not_found(cli
278282
assert response.status_code == 404
279283

280284

281-
def test_request_delete_player_squadnumber_existing_response_status_no_content(client):
285+
def test_request_delete_player_squadnumber_existing_response_status_no_content(
286+
client, nonexistent_player_in_db
287+
):
282288
"""DELETE /players/squadnumber/{squad_number} with existing number returns 204 No Content"""
283-
# Arrange — create the player to be deleted
284-
player = nonexistent_player()
285-
client.post(PATH, json=player.__dict__)
289+
# Arrange
290+
player = nonexistent_player_in_db
286291
# Act
287292
response = client.delete(PATH + "squadnumber/" + str(player.squad_number))
288293
# Assert

0 commit comments

Comments
 (0)