feat(tests): on-hold button with reason modal, Jira comment + On Hold transition
Aegis CI / lint-and-test (push) Waiting to run
Snyk Security Scan / Python vulnerabilities (backend) (push) Waiting to run
Snyk Security Scan / npm vulnerabilities (frontend) (push) Waiting to run
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Waiting to run
Aegis CI / lint-and-test (push) Waiting to run
Snyk Security Scan / Python vulnerabilities (backend) (push) Waiting to run
Snyk Security Scan / npm vulnerabilities (frontend) (push) Waiting to run
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Waiting to run
This commit is contained in:
@@ -56,6 +56,7 @@ from app.schemas.test import (
|
||||
TestBlueValidate,
|
||||
TestClassificationUpdate,
|
||||
TestCreate,
|
||||
TestHold,
|
||||
TestOut,
|
||||
TestRedUpdate,
|
||||
TestRedValidate,
|
||||
@@ -1120,6 +1121,79 @@ def assign_test_operators(
|
||||
return test
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# POST /tests/{id}/hold — place a test on hold (red/blue techs and leads)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@router.post("/{test_id}/hold", response_model=TestOut)
|
||||
def hold_test(
|
||||
test_id: uuid.UUID,
|
||||
payload: TestHold,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(require_any_role("red_tech", "blue_tech", "red_lead", "blue_lead", "admin")),
|
||||
):
|
||||
"""Place a test on hold with a mandatory reason. Posts comment + transitions Jira."""
|
||||
from datetime import datetime as _dt
|
||||
from app.services.jira_service import push_hold_event
|
||||
|
||||
test = crud_get_test_or_raise(db, test_id)
|
||||
|
||||
HOLDABLE_STATES = ("draft", "red_executing", "blue_evaluating")
|
||||
if test.state not in HOLDABLE_STATES:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Cannot hold a test in state '{test.state}'. Only pre-validation states can be held.",
|
||||
)
|
||||
|
||||
if test.is_on_hold:
|
||||
raise HTTPException(status_code=400, detail="Test is already on hold")
|
||||
|
||||
test.is_on_hold = True
|
||||
test.hold_reason = payload.reason
|
||||
test.held_at = _dt.utcnow()
|
||||
|
||||
log_action(db, current_user.id, "hold_test", str(test_id), {"reason": payload.reason})
|
||||
db.commit()
|
||||
db.refresh(test)
|
||||
|
||||
push_hold_event(db, test, current_user, resuming=False, reason=payload.reason)
|
||||
|
||||
return test
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# POST /tests/{id}/resume — resume a test that was on hold
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@router.post("/{test_id}/resume", response_model=TestOut)
|
||||
def resume_test(
|
||||
test_id: uuid.UUID,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(require_any_role("red_tech", "blue_tech", "red_lead", "blue_lead", "admin")),
|
||||
):
|
||||
"""Resume a test that was placed on hold."""
|
||||
from app.services.jira_service import push_hold_event
|
||||
|
||||
test = crud_get_test_or_raise(db, test_id)
|
||||
|
||||
if not test.is_on_hold:
|
||||
raise HTTPException(status_code=400, detail="Test is not on hold")
|
||||
|
||||
test.is_on_hold = False
|
||||
test.hold_reason = None
|
||||
test.held_at = None
|
||||
|
||||
log_action(db, current_user.id, "resume_test", str(test_id), {})
|
||||
db.commit()
|
||||
db.refresh(test)
|
||||
|
||||
push_hold_event(db, test, current_user, resuming=True)
|
||||
|
||||
return test
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# PATCH /tests/{id}/remediation — update remediation fields
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user