version v2
This commit is contained in:
53
README.md
53
README.md
@@ -10,8 +10,9 @@ DocuPulse is a powerful document management system designed to streamline docume
|
|||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
- Node.js (version 18 or higher)
|
- Python 3.11 or higher
|
||||||
- npm or yarn
|
- PostgreSQL 13 or higher
|
||||||
|
- Docker and Docker Compose (for containerized deployment)
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
@@ -23,18 +24,50 @@ cd docupulse
|
|||||||
|
|
||||||
2. Install dependencies:
|
2. Install dependencies:
|
||||||
```bash
|
```bash
|
||||||
npm install
|
pip install -r requirements.txt
|
||||||
# or
|
|
||||||
yarn install
|
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Start the development server:
|
3. Set up environment variables:
|
||||||
```bash
|
```bash
|
||||||
npm run dev
|
# Copy example environment file
|
||||||
# or
|
cp .env.example .env
|
||||||
yarn dev
|
|
||||||
|
# Set version information for local development
|
||||||
|
python set_version.py
|
||||||
```
|
```
|
||||||
|
|
||||||
|
4. Initialize the database:
|
||||||
|
```bash
|
||||||
|
flask db upgrade
|
||||||
|
flask create-admin
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Start the development server:
|
||||||
|
```bash
|
||||||
|
python app.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Version Tracking
|
||||||
|
|
||||||
|
DocuPulse uses a database-only approach for version tracking:
|
||||||
|
|
||||||
|
- **Environment Variables**: Version information is passed via environment variables (`APP_VERSION`, `GIT_COMMIT`, `GIT_BRANCH`, `DEPLOYED_AT`)
|
||||||
|
- **Database Storage**: Instance version information is stored in the `instances` table
|
||||||
|
- **API Endpoint**: Version information is available via `/api/version`
|
||||||
|
|
||||||
|
### Setting Version Information
|
||||||
|
|
||||||
|
For local development:
|
||||||
|
```bash
|
||||||
|
python set_version.py
|
||||||
|
```
|
||||||
|
|
||||||
|
For production deployments, set the following environment variables:
|
||||||
|
- `APP_VERSION`: Application version/tag
|
||||||
|
- `GIT_COMMIT`: Git commit hash
|
||||||
|
- `GIT_BRANCH`: Git branch name
|
||||||
|
- `DEPLOYED_AT`: Deployment timestamp
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Document upload and management
|
- Document upload and management
|
||||||
@@ -42,6 +75,8 @@ yarn dev
|
|||||||
- Secure document storage
|
- Secure document storage
|
||||||
- User authentication and authorization
|
- User authentication and authorization
|
||||||
- Document version control
|
- Document version control
|
||||||
|
- Multi-tenant instance management
|
||||||
|
- RESTful API
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ services:
|
|||||||
- POSTGRES_PASSWORD=docupulse_${PORT:-10335}
|
- POSTGRES_PASSWORD=docupulse_${PORT:-10335}
|
||||||
- POSTGRES_DB=docupulse_${PORT:-10335}
|
- POSTGRES_DB=docupulse_${PORT:-10335}
|
||||||
- MASTER=${ISMASTER:-false}
|
- MASTER=${ISMASTER:-false}
|
||||||
|
- APP_VERSION=${APP_VERSION:-unknown}
|
||||||
|
- GIT_COMMIT=${GIT_COMMIT:-unknown}
|
||||||
|
- GIT_BRANCH=${GIT_BRANCH:-unknown}
|
||||||
|
- DEPLOYED_AT=${DEPLOYED_AT:-unknown}
|
||||||
volumes:
|
volumes:
|
||||||
- docupulse_uploads:/app/uploads
|
- docupulse_uploads:/app/uploads
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|||||||
Binary file not shown.
@@ -761,48 +761,6 @@ def download_docker_compose():
|
|||||||
else:
|
else:
|
||||||
content = response.text
|
content = response.text
|
||||||
|
|
||||||
# Add version.txt creation to the docker-compose content
|
|
||||||
if commit_hash:
|
|
||||||
# Create version information with both tag and commit hash
|
|
||||||
version_info = {
|
|
||||||
'tag': latest_tag or 'unknown',
|
|
||||||
'commit': commit_hash,
|
|
||||||
'branch': data['branch'],
|
|
||||||
'deployed_at': datetime.utcnow().isoformat()
|
|
||||||
}
|
|
||||||
version_json = json.dumps(version_info, indent=2)
|
|
||||||
|
|
||||||
# Add a command to create version.txt with the version information
|
|
||||||
version_command = f'echo \'{version_json}\' > /app/version.txt'
|
|
||||||
|
|
||||||
# Find the web service and add the command
|
|
||||||
if 'web:' in content:
|
|
||||||
# Add the command to create version.txt before the main command
|
|
||||||
lines = content.split('\n')
|
|
||||||
new_lines = []
|
|
||||||
in_web_service = False
|
|
||||||
command_added = False
|
|
||||||
|
|
||||||
for line in lines:
|
|
||||||
new_lines.append(line)
|
|
||||||
|
|
||||||
if line.strip() == 'web:':
|
|
||||||
in_web_service = True
|
|
||||||
elif in_web_service and line.strip().startswith('command:'):
|
|
||||||
# Add the version.txt creation command before the main command
|
|
||||||
new_lines.append(f' - sh -c "{version_command} && {line.split("command:")[1].strip()}"')
|
|
||||||
command_added = True
|
|
||||||
continue
|
|
||||||
elif in_web_service and line.strip() and not line.startswith(' ') and not line.startswith('#'):
|
|
||||||
# We've left the web service section
|
|
||||||
if not command_added:
|
|
||||||
# If no command was found, add a new command section
|
|
||||||
new_lines.append(f' command: sh -c "{version_command} && python app.py"')
|
|
||||||
command_added = True
|
|
||||||
in_web_service = False
|
|
||||||
|
|
||||||
content = '\n'.join(new_lines)
|
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'success': True,
|
'success': True,
|
||||||
'content': content,
|
'content': content,
|
||||||
|
|||||||
@@ -1983,32 +1983,16 @@ def init_routes(main_bp):
|
|||||||
|
|
||||||
@main_bp.route('/api/version')
|
@main_bp.route('/api/version')
|
||||||
def api_version():
|
def api_version():
|
||||||
version_file = os.path.join(current_app.root_path, 'version.txt')
|
# Get version information from environment variables
|
||||||
version = 'unknown'
|
version = os.getenv('APP_VERSION', 'unknown')
|
||||||
version_data = {}
|
commit = os.getenv('GIT_COMMIT', 'unknown')
|
||||||
|
branch = os.getenv('GIT_BRANCH', 'unknown')
|
||||||
if os.path.exists(version_file):
|
deployed_at = os.getenv('DEPLOYED_AT', 'unknown')
|
||||||
with open(version_file, 'r') as f:
|
|
||||||
content = f.read().strip()
|
|
||||||
|
|
||||||
# Try to parse as JSON first (new format)
|
|
||||||
try:
|
|
||||||
version_data = json.loads(content)
|
|
||||||
version = version_data.get('tag', 'unknown')
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
# Fallback to old format (just commit hash)
|
|
||||||
version = content
|
|
||||||
version_data = {
|
|
||||||
'tag': 'unknown',
|
|
||||||
'commit': content,
|
|
||||||
'branch': 'unknown',
|
|
||||||
'deployed_at': 'unknown'
|
|
||||||
}
|
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'version': version,
|
'version': version,
|
||||||
'tag': version_data.get('tag', 'unknown'),
|
'tag': version,
|
||||||
'commit': version_data.get('commit', 'unknown'),
|
'commit': commit,
|
||||||
'branch': version_data.get('branch', 'unknown'),
|
'branch': branch,
|
||||||
'deployed_at': version_data.get('deployed_at', 'unknown')
|
'deployed_at': deployed_at
|
||||||
})
|
})
|
||||||
59
set_version.py
Normal file
59
set_version.py
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Utility script to set version environment variables for local development.
|
||||||
|
This replaces the need for version.txt file creation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
def get_git_info():
|
||||||
|
"""Get current git commit hash and branch"""
|
||||||
|
try:
|
||||||
|
# Get current commit hash
|
||||||
|
commit_hash = subprocess.check_output(['git', 'rev-parse', 'HEAD'],
|
||||||
|
text=True, stderr=subprocess.DEVNULL).strip()
|
||||||
|
|
||||||
|
# Get current branch
|
||||||
|
branch = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
|
||||||
|
text=True, stderr=subprocess.DEVNULL).strip()
|
||||||
|
|
||||||
|
# Get latest tag
|
||||||
|
try:
|
||||||
|
latest_tag = subprocess.check_output(['git', 'describe', '--tags', '--abbrev=0'],
|
||||||
|
text=True, stderr=subprocess.DEVNULL).strip()
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
latest_tag = 'unknown'
|
||||||
|
|
||||||
|
return {
|
||||||
|
'commit': commit_hash,
|
||||||
|
'branch': branch,
|
||||||
|
'tag': latest_tag
|
||||||
|
}
|
||||||
|
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||||
|
return {
|
||||||
|
'commit': 'unknown',
|
||||||
|
'branch': 'unknown',
|
||||||
|
'tag': 'unknown'
|
||||||
|
}
|
||||||
|
|
||||||
|
def set_version_env():
|
||||||
|
"""Set version environment variables"""
|
||||||
|
git_info = get_git_info()
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
os.environ['APP_VERSION'] = git_info['tag']
|
||||||
|
os.environ['GIT_COMMIT'] = git_info['commit']
|
||||||
|
os.environ['GIT_BRANCH'] = git_info['branch']
|
||||||
|
os.environ['DEPLOYED_AT'] = datetime.utcnow().isoformat()
|
||||||
|
|
||||||
|
print("Version environment variables set:")
|
||||||
|
print(f"APP_VERSION: {os.environ['APP_VERSION']}")
|
||||||
|
print(f"GIT_COMMIT: {os.environ['GIT_COMMIT']}")
|
||||||
|
print(f"GIT_BRANCH: {os.environ['GIT_BRANCH']}")
|
||||||
|
print(f"DEPLOYED_AT: {os.environ['DEPLOYED_AT']}")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
set_version_env()
|
||||||
@@ -451,6 +451,11 @@ async function startLaunch(data) {
|
|||||||
throw new Error(dockerComposeResult.error || 'Failed to download docker-compose.yml');
|
throw new Error(dockerComposeResult.error || 'Failed to download docker-compose.yml');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set global version variables for deployment
|
||||||
|
window.currentDeploymentVersion = dockerComposeResult.latest_tag || dockerComposeResult.commit_hash || 'unknown';
|
||||||
|
window.currentDeploymentCommit = dockerComposeResult.commit_hash || 'unknown';
|
||||||
|
window.currentDeploymentBranch = data.branch;
|
||||||
|
|
||||||
// Update the step to show success
|
// Update the step to show success
|
||||||
const dockerComposeStep = document.querySelectorAll('.step-item')[7];
|
const dockerComposeStep = document.querySelectorAll('.step-item')[7];
|
||||||
dockerComposeStep.classList.remove('active');
|
dockerComposeStep.classList.remove('active');
|
||||||
@@ -2551,6 +2556,22 @@ async function deployStack(dockerComposeContent, stackName, port) {
|
|||||||
{
|
{
|
||||||
name: 'ISMASTER',
|
name: 'ISMASTER',
|
||||||
value: 'false'
|
value: 'false'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'APP_VERSION',
|
||||||
|
value: window.currentDeploymentVersion || 'unknown'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'GIT_COMMIT',
|
||||||
|
value: window.currentDeploymentCommit || 'unknown'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'GIT_BRANCH',
|
||||||
|
value: window.currentDeploymentBranch || 'unknown'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'DEPLOYED_AT',
|
||||||
|
value: new Date().toISOString()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
@@ -2573,34 +2594,9 @@ async function deployStack(dockerComposeContent, stackName, port) {
|
|||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error deploying stack:', error);
|
console.error('Error deploying stack:', error);
|
||||||
|
|
||||||
// Check if this is a timeout error
|
|
||||||
if (error.name === 'AbortError') {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: 'Stack deployment timed out after 10 minutes. The operation may still be in progress.'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this is a network error
|
|
||||||
if (error.message && error.message.includes('fetch')) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: 'Network error during stack deployment. Please check your connection and try again.'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this is a response error
|
|
||||||
if (error.message && error.message.includes('Failed to deploy stack')) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: error.message
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: error.message || 'Unknown error during stack deployment'
|
error: error.message
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,38 @@
|
|||||||
.table td {
|
.table td {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Version column styling */
|
||||||
|
.version-badge {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.branch-badge {
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make table responsive */
|
||||||
|
.table-responsive {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tooltip styling for version info */
|
||||||
|
.tooltip-inner {
|
||||||
|
max-width: 300px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Version comparison styling */
|
||||||
|
.version-outdated {
|
||||||
|
background-color: #fff3cd !important;
|
||||||
|
border-color: #ffeaa7 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-current {
|
||||||
|
background-color: #d1ecf1 !important;
|
||||||
|
border-color: #bee5eb !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@@ -51,6 +83,8 @@
|
|||||||
<th>Payment Plan</th>
|
<th>Payment Plan</th>
|
||||||
<th>Main URL</th>
|
<th>Main URL</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
|
<th>Version</th>
|
||||||
|
<th>Branch</th>
|
||||||
<th>Connection Token</th>
|
<th>Connection Token</th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -82,6 +116,26 @@
|
|||||||
{{ instance.status|title }}
|
{{ instance.status|title }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if instance.deployed_version %}
|
||||||
|
<span class="badge bg-info version-badge" data-bs-toggle="tooltip"
|
||||||
|
title="Deployed: {{ instance.deployed_version }}{% if instance.version_checked_at %}<br>Checked: {{ instance.version_checked_at.strftime('%Y-%m-%d %H:%M') }}{% endif %}">
|
||||||
|
{{ instance.deployed_version[:8] if instance.deployed_version != 'unknown' else 'unknown' }}
|
||||||
|
</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="badge bg-secondary version-badge">unknown</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if instance.deployed_branch %}
|
||||||
|
<span class="badge bg-light text-dark branch-badge" data-bs-toggle="tooltip"
|
||||||
|
title="Deployed branch: {{ instance.deployed_branch }}">
|
||||||
|
{{ instance.deployed_branch }}
|
||||||
|
</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="badge bg-secondary branch-badge">unknown</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{% if instance.connection_token %}
|
{% if instance.connection_token %}
|
||||||
<span class="badge bg-success" data-bs-toggle="tooltip" title="Instance is authenticated">
|
<span class="badge bg-success" data-bs-toggle="tooltip" title="Instance is authenticated">
|
||||||
@@ -809,19 +863,19 @@ async function fetchInstanceStats(instanceUrl, instanceId, jwtToken) {
|
|||||||
|
|
||||||
const row = document.querySelector(`[data-instance-id="${instanceId}"]`).closest('tr');
|
const row = document.querySelector(`[data-instance-id="${instanceId}"]`).closest('tr');
|
||||||
|
|
||||||
// Update rooms count
|
// Update rooms count (3rd column)
|
||||||
const roomsCell = row.querySelector('td:nth-child(3)');
|
const roomsCell = row.querySelector('td:nth-child(3)');
|
||||||
if (roomsCell) {
|
if (roomsCell) {
|
||||||
roomsCell.textContent = data.rooms || '0';
|
roomsCell.textContent = data.rooms || '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update conversations count
|
// Update conversations count (4th column)
|
||||||
const conversationsCell = row.querySelector('td:nth-child(4)');
|
const conversationsCell = row.querySelector('td:nth-child(4)');
|
||||||
if (conversationsCell) {
|
if (conversationsCell) {
|
||||||
conversationsCell.textContent = data.conversations || '0';
|
conversationsCell.textContent = data.conversations || '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update data usage
|
// Update data usage (5th column)
|
||||||
const dataCell = row.querySelector('td:nth-child(5)');
|
const dataCell = row.querySelector('td:nth-child(5)');
|
||||||
if (dataCell) {
|
if (dataCell) {
|
||||||
const dataSize = data.total_storage || 0;
|
const dataSize = data.total_storage || 0;
|
||||||
@@ -940,8 +994,8 @@ async function fetchCompanyNames() {
|
|||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
|
|
||||||
// Changed from nth-child(8) to nth-child(7) since Main URL is the 7th column
|
// Main URL is now the 9th column (after adding Version and Branch columns)
|
||||||
const urlCell = row.querySelector('td:nth-child(7)');
|
const urlCell = row.querySelector('td:nth-child(9)');
|
||||||
|
|
||||||
if (!urlCell) {
|
if (!urlCell) {
|
||||||
console.error(`Could not find URL cell for instance ${instanceId}`);
|
console.error(`Could not find URL cell for instance ${instanceId}`);
|
||||||
@@ -1056,8 +1110,8 @@ async function editInstance(id) {
|
|||||||
// Get the name from the first cell
|
// Get the name from the first cell
|
||||||
const name = row.querySelector('td:first-child').textContent.trim();
|
const name = row.querySelector('td:first-child').textContent.trim();
|
||||||
|
|
||||||
// Get the main URL from the link in the URL cell (7th column)
|
// Get the main URL from the link in the URL cell (9th column after adding Version and Branch)
|
||||||
const urlCell = row.querySelector('td:nth-child(7)');
|
const urlCell = row.querySelector('td:nth-child(9)');
|
||||||
const urlLink = urlCell.querySelector('a');
|
const urlLink = urlCell.querySelector('a');
|
||||||
const mainUrl = urlLink ? urlLink.getAttribute('href') : urlCell.textContent.trim();
|
const mainUrl = urlLink ? urlLink.getAttribute('href') : urlCell.textContent.trim();
|
||||||
|
|
||||||
|
|||||||
@@ -297,6 +297,67 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Version Management -->
|
||||||
|
<div class="mb-5">
|
||||||
|
<h5 style="color: var(--primary-color);" class="mb-4">Version Management</h5>
|
||||||
|
|
||||||
|
<!-- Version Tracking -->
|
||||||
|
<div class="card border-0 shadow-sm mb-4">
|
||||||
|
<div class="card-header bg-white">
|
||||||
|
<h6 class="mb-0" style="color: var(--primary-color);">
|
||||||
|
<i class="fas fa-tags me-2"></i>Version Tracking
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h6 class="text-muted mb-2">Environment Variables</h6>
|
||||||
|
<ul class="list-unstyled small">
|
||||||
|
<li class="mb-1">• <code>APP_VERSION</code> - Application version/tag</li>
|
||||||
|
<li class="mb-1">• <code>GIT_COMMIT</code> - Git commit hash</li>
|
||||||
|
<li class="mb-1">• <code>GIT_BRANCH</code> - Git branch name</li>
|
||||||
|
<li class="mb-1">• <code>DEPLOYED_AT</code> - Deployment timestamp</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h6 class="text-muted mb-2">Database Storage</h6>
|
||||||
|
<ul class="list-unstyled small">
|
||||||
|
<li class="mb-1">• Instance version tracking</li>
|
||||||
|
<li class="mb-1">• Version comparison</li>
|
||||||
|
<li class="mb-1">• Update notifications</li>
|
||||||
|
<li class="mb-1">• Deployment history</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Version API -->
|
||||||
|
<div class="card border-0 shadow-sm mb-4">
|
||||||
|
<div class="card-header bg-white">
|
||||||
|
<h6 class="mb-0" style="color: var(--primary-color);">
|
||||||
|
<i class="fas fa-code me-2"></i>Version API
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="mb-3">
|
||||||
|
<h6 class="text-muted mb-2">Endpoint</h6>
|
||||||
|
<code class="bg-light p-2 rounded d-block">GET /api/version</code>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<h6 class="text-muted mb-2">Response</h6>
|
||||||
|
<pre class="bg-light p-2 rounded small"><code>{
|
||||||
|
"version": "v1.2.3",
|
||||||
|
"tag": "v1.2.3",
|
||||||
|
"commit": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0",
|
||||||
|
"branch": "main",
|
||||||
|
"deployed_at": "2024-01-15T10:30:00.000000"
|
||||||
|
}</code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
|
|||||||
55
test_version_api.py
Normal file
55
test_version_api.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test script for the new version API endpoint.
|
||||||
|
This verifies that the database-only version tracking works correctly.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
def test_version_api():
|
||||||
|
"""Test the version API endpoint"""
|
||||||
|
|
||||||
|
# Set test environment variables
|
||||||
|
os.environ['APP_VERSION'] = 'v1.2.3'
|
||||||
|
os.environ['GIT_COMMIT'] = 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0'
|
||||||
|
os.environ['GIT_BRANCH'] = 'main'
|
||||||
|
os.environ['DEPLOYED_AT'] = datetime.utcnow().isoformat()
|
||||||
|
|
||||||
|
print("Testing version API endpoint...")
|
||||||
|
print(f"APP_VERSION: {os.environ['APP_VERSION']}")
|
||||||
|
print(f"GIT_COMMIT: {os.environ['GIT_COMMIT']}")
|
||||||
|
print(f"GIT_BRANCH: {os.environ['GIT_BRANCH']}")
|
||||||
|
print(f"DEPLOYED_AT: {os.environ['DEPLOYED_AT']}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Test the API endpoint (assuming it's running on localhost:5000)
|
||||||
|
response = requests.get('http://localhost:5000/api/version')
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
data = response.json()
|
||||||
|
print("\n✅ Version API test successful!")
|
||||||
|
print("Response:")
|
||||||
|
print(json.dumps(data, indent=2))
|
||||||
|
|
||||||
|
# Verify the response matches our environment variables
|
||||||
|
assert data['version'] == os.environ['APP_VERSION'], f"Version mismatch: {data['version']} != {os.environ['APP_VERSION']}"
|
||||||
|
assert data['commit'] == os.environ['GIT_COMMIT'], f"Commit mismatch: {data['commit']} != {os.environ['GIT_COMMIT']}"
|
||||||
|
assert data['branch'] == os.environ['GIT_BRANCH'], f"Branch mismatch: {data['branch']} != {os.environ['GIT_BRANCH']}"
|
||||||
|
assert data['deployed_at'] == os.environ['DEPLOYED_AT'], f"Deployed at mismatch: {data['deployed_at']} != {os.environ['DEPLOYED_AT']}"
|
||||||
|
|
||||||
|
print("\n✅ All version information matches environment variables!")
|
||||||
|
|
||||||
|
else:
|
||||||
|
print(f"\n❌ Version API test failed with status code: {response.status_code}")
|
||||||
|
print(f"Response: {response.text}")
|
||||||
|
|
||||||
|
except requests.exceptions.ConnectionError:
|
||||||
|
print("\n❌ Could not connect to the API. Make sure the application is running on localhost:5000")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n❌ Test failed with error: {str(e)}")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test_version_api()
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"tag": "v1.2.3",
|
|
||||||
"commit": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0",
|
|
||||||
"branch": "main",
|
|
||||||
"deployed_at": "2024-01-15T10:30:00.000000"
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user