Add deployment safeguards to prevent code mismatch issues
- Add /api/version endpoint with git commit and file checksums - Create automated deploy.ps1 script with pre-flight checks - Document file dependencies to prevent partial deployments - Add version verification before and after deployment Prevents: 4-hour debugging sessions due to production/local mismatch Ensures: All dependent files deploy together atomically Verifies: Production matches local code after deployment
This commit is contained in:
91
api/routers/version.py
Normal file
91
api/routers/version.py
Normal file
@@ -0,0 +1,91 @@
|
||||
"""
|
||||
Version endpoint for ClaudeTools API.
|
||||
Returns version information to detect code mismatches.
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter
|
||||
from datetime import datetime
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get(
|
||||
"/version",
|
||||
response_model=dict,
|
||||
summary="Get API version information",
|
||||
description="Returns version, git commit, and deployment timestamp",
|
||||
)
|
||||
def get_version():
|
||||
"""
|
||||
Get API version information.
|
||||
|
||||
Returns:
|
||||
dict: Version info including git commit, branch, deployment time
|
||||
"""
|
||||
version_info = {
|
||||
"api_version": "1.0.0",
|
||||
"component": "claudetools-api",
|
||||
"deployment_timestamp": datetime.utcnow().isoformat() + "Z"
|
||||
}
|
||||
|
||||
# Try to get git information
|
||||
try:
|
||||
# Get current commit hash
|
||||
result = subprocess.run(
|
||||
["git", "rev-parse", "HEAD"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5,
|
||||
cwd=os.path.dirname(os.path.dirname(__file__))
|
||||
)
|
||||
if result.returncode == 0:
|
||||
version_info["git_commit"] = result.stdout.strip()
|
||||
version_info["git_commit_short"] = result.stdout.strip()[:7]
|
||||
|
||||
# Get current branch
|
||||
result = subprocess.run(
|
||||
["git", "rev-parse", "--abbrev-ref", "HEAD"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5,
|
||||
cwd=os.path.dirname(os.path.dirname(__file__))
|
||||
)
|
||||
if result.returncode == 0:
|
||||
version_info["git_branch"] = result.stdout.strip()
|
||||
|
||||
# Get last commit date
|
||||
result = subprocess.run(
|
||||
["git", "log", "-1", "--format=%ci"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5,
|
||||
cwd=os.path.dirname(os.path.dirname(__file__))
|
||||
)
|
||||
if result.returncode == 0:
|
||||
version_info["last_commit_date"] = result.stdout.strip()
|
||||
|
||||
except Exception:
|
||||
version_info["git_info"] = "Not available (not a git repository)"
|
||||
|
||||
# Add file checksums for critical files
|
||||
import hashlib
|
||||
critical_files = [
|
||||
"api/routers/conversation_contexts.py",
|
||||
"api/services/conversation_context_service.py"
|
||||
]
|
||||
|
||||
checksums = {}
|
||||
base_dir = os.path.dirname(os.path.dirname(__file__))
|
||||
for file_path in critical_files:
|
||||
full_path = os.path.join(base_dir, file_path)
|
||||
try:
|
||||
with open(full_path, 'rb') as f:
|
||||
checksums[file_path] = hashlib.md5(f.read()).hexdigest()[:8]
|
||||
except Exception:
|
||||
checksums[file_path] = "not_found"
|
||||
|
||||
version_info["file_checksums"] = checksums
|
||||
|
||||
return version_info
|
||||
Reference in New Issue
Block a user