Compare commits
22 Commits
v3.1.1
...
f21d05f404
Author | SHA1 | Date | |
---|---|---|---|
f21d05f404 | |||
ff447292f0 | |||
da4545c6d8 | |||
e0ff8c89fb | |||
5579637995 | |||
1816b6e14a | |||
8dedc9303b | |||
94c6db9b72 | |||
0afb57789b | |||
02a0f479dc | |||
841a5a492c | |||
17a716fcd0 | |||
7c04871fdd | |||
af53f68d2c | |||
985f9754c4 | |||
4ed5f2ccad | |||
123ec13896 | |||
4a30af60e8 | |||
e5d5284ee3 | |||
cd74cd6d10 | |||
9c6fedc149 | |||
40aef686af |
@@ -28,6 +28,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
@@ -98,6 +100,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
@@ -134,6 +138,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
@@ -193,6 +199,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
- name: Wait for VictoriaMetrics
|
- name: Wait for VictoriaMetrics
|
||||||
run: |
|
run: |
|
||||||
@@ -244,6 +252,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
- name: Deploy to staging
|
- name: Deploy to staging
|
||||||
run: |
|
run: |
|
||||||
@@ -269,6 +279,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
- name: Deploy to production
|
- name: Deploy to production
|
||||||
run: |
|
run: |
|
||||||
@@ -296,6 +308,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
- name: Install Apache Bench
|
- name: Install Apache Bench
|
||||||
run: |
|
run: |
|
||||||
|
@@ -27,6 +27,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
@@ -127,6 +129,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
@@ -224,6 +228,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
@@ -248,8 +254,8 @@ jobs:
|
|||||||
project = 'Northern Thailand Ping River Monitor'
|
project = 'Northern Thailand Ping River Monitor'
|
||||||
copyright = '2025, Ping River Monitor Team'
|
copyright = '2025, Ping River Monitor Team'
|
||||||
author = 'Ping River Monitor Team'
|
author = 'Ping River Monitor Team'
|
||||||
version = '3.1.1'
|
version = '3.1.3'
|
||||||
release = '3.1.1'
|
release = '3.1.3'
|
||||||
|
|
||||||
extensions = [
|
extensions = [
|
||||||
'sphinx.ext.autodoc',
|
'sphinx.ext.autodoc',
|
||||||
|
@@ -7,7 +7,7 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
version:
|
version:
|
||||||
description: 'Release version (e.g., v3.1.1)'
|
description: 'Release version (e.g., v3.1.3)'
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
@@ -30,6 +30,7 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Get version
|
- name: Get version
|
||||||
@@ -75,6 +76,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
@@ -113,6 +116,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
@@ -121,8 +126,8 @@ jobs:
|
|||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ vars.WORKER_USERNAME}}
|
||||||
password: ${{ secrets.GITEA_TOKEN }}
|
password: ${{ secrets.CI_BOT_TOKEN }}
|
||||||
|
|
||||||
- name: Build and push release images
|
- name: Build and push release images
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
@@ -142,7 +147,7 @@ jobs:
|
|||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
# Security scan for release
|
# Security scan for release
|
||||||
security-scan:
|
security-scan:
|
||||||
@@ -153,144 +158,127 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Run Trivy vulnerability scanner
|
|
||||||
uses: aquasecurity/trivy-action@master
|
|
||||||
with:
|
with:
|
||||||
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-release.outputs.version }}
|
token: ${{ secrets.GITEA_TOKEN}}
|
||||||
format: 'sarif'
|
|
||||||
output: 'trivy-results.sarif'
|
|
||||||
github-token: ${{ secrets.GH_TOKEN }}
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
|
|
||||||
- name: Upload Trivy scan results
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: security-scan-results
|
|
||||||
path: trivy-results.sarif
|
|
||||||
|
|
||||||
# Deploy release to production
|
|
||||||
|
# Test release deployment locally
|
||||||
deploy-release:
|
deploy-release:
|
||||||
name: Deploy Release
|
name: Test Release Deployment
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [create-release, build-release, security-scan]
|
needs: [create-release, build-release, security-scan]
|
||||||
environment:
|
environment:
|
||||||
name: production
|
name: testing
|
||||||
url: https://ping-river-monitor.b4l.co.th
|
url: http://localhost:8080
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
- name: Deploy to production
|
- name: Log in to Container Registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ vars.WORKER_USERNAME}}
|
||||||
|
password: ${{ secrets.CI_BOT_TOKEN }}
|
||||||
|
|
||||||
|
- name: Deploy to production (Local Test)
|
||||||
run: |
|
run: |
|
||||||
echo "🚀 Deploying ${{ needs.create-release.outputs.version }} to production..."
|
echo "🚀 Testing ${{ needs.create-release.outputs.version }} deployment locally..."
|
||||||
|
|
||||||
# Example deployment commands (customize for your infrastructure)
|
# Pull the built image
|
||||||
# kubectl set image deployment/ping-river-monitor app=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-release.outputs.version }}
|
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-release.outputs.version }}
|
||||||
# docker-compose pull && docker-compose up -d
|
|
||||||
# Or webhook call to your deployment system
|
|
||||||
|
|
||||||
echo "✅ Deployment initiated"
|
# Stop any existing containers
|
||||||
|
docker stop ping-river-monitor-test || true
|
||||||
|
docker rm ping-river-monitor-test || true
|
||||||
|
|
||||||
|
# Start the container for testing
|
||||||
|
docker run -d \
|
||||||
|
--name ping-river-monitor-test \
|
||||||
|
-p 8080:8000 \
|
||||||
|
-e LOG_LEVEL=INFO \
|
||||||
|
-e DB_TYPE=sqlite \
|
||||||
|
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-release.outputs.version }}
|
||||||
|
|
||||||
|
echo "✅ Container started for testing"
|
||||||
|
|
||||||
- name: Health check after deployment
|
- name: Health check after deployment
|
||||||
run: |
|
run: |
|
||||||
echo "⏳ Waiting for deployment to stabilize..."
|
echo "⏳ Waiting for application to start..."
|
||||||
sleep 60
|
sleep 30
|
||||||
|
|
||||||
echo "🔍 Running health checks..."
|
echo "🔍 Running health checks against local container..."
|
||||||
curl -f https://ping-river-monitor.b4l.co.th/health
|
|
||||||
curl -f https://ping-river-monitor.b4l.co.th/stations
|
|
||||||
|
|
||||||
echo "✅ Health checks passed!"
|
# Wait for the application to be ready
|
||||||
|
for i in {1..12}; do
|
||||||
|
if curl -f http://localhost:8080/health; then
|
||||||
|
echo "✅ Health endpoint responding"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
echo "⏳ Waiting for health endpoint... (attempt $i/12)"
|
||||||
|
sleep 10
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
- name: Update deployment status
|
# Test API endpoints
|
||||||
|
echo "🧪 Testing API endpoints..."
|
||||||
|
curl -f http://localhost:8080/health || exit 1
|
||||||
|
curl -f http://localhost:8080/docs || exit 1
|
||||||
|
curl -f http://localhost:8080/stations || exit 1
|
||||||
|
curl -f http://localhost:8080/metrics || exit 1
|
||||||
|
|
||||||
|
echo "✅ All health checks passed!"
|
||||||
|
|
||||||
|
- name: Container logs and cleanup
|
||||||
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
echo "📊 Deployment Summary:"
|
echo "📋 Container logs:"
|
||||||
|
docker logs ping-river-monitor-test || true
|
||||||
|
|
||||||
|
echo "🧹 Cleaning up test container..."
|
||||||
|
docker stop ping-river-monitor-test || true
|
||||||
|
docker rm ping-river-monitor-test || true
|
||||||
|
|
||||||
|
echo "📊 Deployment Test Summary:"
|
||||||
echo "Version: ${{ needs.create-release.outputs.version }}"
|
echo "Version: ${{ needs.create-release.outputs.version }}"
|
||||||
echo "Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-release.outputs.version }}"
|
echo "Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-release.outputs.version }}"
|
||||||
echo "URL: https://ping-river-monitor.b4l.co.th"
|
echo "Status: Container tested successfully"
|
||||||
echo "Grafana: https://grafana.ping-river-monitor.b4l.co.th"
|
echo "Ready for production deployment"
|
||||||
echo "API Docs: https://ping-river-monitor.b4l.co.th/docs"
|
|
||||||
|
|
||||||
# Post-release validation
|
|
||||||
validate-release:
|
|
||||||
name: Validate Release
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: deploy-release
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Comprehensive API test
|
|
||||||
run: |
|
|
||||||
echo "🧪 Running comprehensive API tests..."
|
|
||||||
|
|
||||||
# Test all major endpoints
|
|
||||||
curl -f https://ping-river-monitor.b4l.co.th/health
|
|
||||||
curl -f https://ping-river-monitor.b4l.co.th/metrics
|
|
||||||
curl -f https://ping-river-monitor.b4l.co.th/stations
|
|
||||||
curl -f https://ping-river-monitor.b4l.co.th/measurements/latest?limit=5
|
|
||||||
curl -f https://ping-river-monitor.b4l.co.th/scraping/status
|
|
||||||
|
|
||||||
echo "✅ All API endpoints responding correctly"
|
|
||||||
|
|
||||||
- name: Performance validation
|
|
||||||
run: |
|
|
||||||
echo "⚡ Running performance validation..."
|
|
||||||
|
|
||||||
# Install Apache Bench
|
|
||||||
sudo apt-get update && sudo apt-get install -y apache2-utils
|
|
||||||
|
|
||||||
# Test response times
|
|
||||||
ab -n 10 -c 2 https://ping-river-monitor.b4l.co.th/health
|
|
||||||
ab -n 10 -c 2 https://ping-river-monitor.b4l.co.th/stations
|
|
||||||
|
|
||||||
echo "✅ Performance validation completed"
|
|
||||||
|
|
||||||
- name: Data validation
|
|
||||||
run: |
|
|
||||||
echo "📊 Validating data collection..."
|
|
||||||
|
|
||||||
# Check if recent data is available
|
|
||||||
response=$(curl -s https://ping-river-monitor.b4l.co.th/measurements/latest?limit=1)
|
|
||||||
echo "Latest measurement: $response"
|
|
||||||
|
|
||||||
# Validate data structure (basic check)
|
|
||||||
if echo "$response" | grep -q "water_level"; then
|
|
||||||
echo "✅ Data structure validation passed"
|
|
||||||
else
|
|
||||||
echo "❌ Data structure validation failed"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Notify stakeholders
|
# Notify stakeholders
|
||||||
notify:
|
notify:
|
||||||
name: Notify Release
|
name: Notify Release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [create-release, validate-release]
|
needs: [create-release, deploy-release]
|
||||||
if: always()
|
if: always()
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Notify success
|
- name: Notify success
|
||||||
if: needs.validate-release.result == 'success'
|
if: needs.deploy-release.result == 'success'
|
||||||
run: |
|
run: |
|
||||||
echo "🎉 Release ${{ needs.create-release.outputs.version }} deployed successfully!"
|
echo "🎉 Release ${{ needs.create-release.outputs.version }} tested successfully!"
|
||||||
echo "🌐 Production URL: https://ping-river-monitor.b4l.co.th"
|
echo "🧪 Local Test: Passed all health checks"
|
||||||
echo "📊 Grafana: https://grafana.ping-river-monitor.b4l.co.th"
|
echo "<EFBFBD> GDocker Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-release.outputs.version }}"
|
||||||
echo "📚 API Docs: https://ping-river-monitor.b4l.co.th/docs"
|
echo "✅ Ready for production deployment"
|
||||||
|
|
||||||
# Add notification to Slack, Discord, email, etc.
|
# Add notification to Slack, Discord, email, etc.
|
||||||
# curl -X POST -H 'Content-type: application/json' \
|
# curl -X POST -H 'Content-type: application/json' \
|
||||||
# --data '{"text":"🎉 Northern Thailand Ping River Monitor ${{ needs.create-release.outputs.version }} deployed successfully!"}' \
|
# --data '{"text":"🎉 Northern Thailand Ping River Monitor ${{ needs.create-release.outputs.version }} tested and ready for deployment!"}' \
|
||||||
# ${{ secrets.SLACK_WEBHOOK_URL }}
|
# ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||||
|
|
||||||
- name: Notify failure
|
- name: Notify failure
|
||||||
if: needs.validate-release.result == 'failure'
|
if: needs.deploy-release.result == 'failure'
|
||||||
run: |
|
run: |
|
||||||
echo "❌ Release ${{ needs.create-release.outputs.version }} deployment failed!"
|
echo "❌ Release ${{ needs.create-release.outputs.version }} testing failed!"
|
||||||
echo "Please check the logs and take corrective action."
|
echo "Please check the logs and fix issues before production deployment."
|
||||||
|
|
||||||
# Add failure notification
|
# Add failure notification
|
||||||
# curl -X POST -H 'Content-type: application/json' \
|
# curl -X POST -H 'Content-type: application/json' \
|
||||||
# --data '{"text":"❌ Northern Thailand Ping River Monitor ${{ needs.create-release.outputs.version }} deployment failed!"}' \
|
# --data '{"text":"❌ Northern Thailand Ping River Monitor ${{ needs.create-release.outputs.version }} testing failed!"}' \
|
||||||
# ${{ secrets.SLACK_WEBHOOK_URL }}
|
# ${{ secrets.SLACK_WEBHOOK_URL }}
|
@@ -25,6 +25,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
@@ -61,16 +63,16 @@ jobs:
|
|||||||
|
|
||||||
- name: Check for critical vulnerabilities
|
- name: Check for critical vulnerabilities
|
||||||
run: |
|
run: |
|
||||||
echo "🔍 Checking for critical vulnerabilities..."
|
echo "Checking for critical vulnerabilities..."
|
||||||
|
|
||||||
# Check Safety results
|
# Check Safety results
|
||||||
if [ -f safety-report.json ]; then
|
if [ -f safety-report.json ]; then
|
||||||
critical_count=$(jq '.vulnerabilities | length' safety-report.json 2>/dev/null || echo "0")
|
critical_count=$(jq '.vulnerabilities | length' safety-report.json 2>/dev/null || echo "0")
|
||||||
if [ "$critical_count" -gt 0 ]; then
|
if [ "$critical_count" -gt 0 ]; then
|
||||||
echo "⚠️ Found $critical_count dependency vulnerabilities"
|
echo "Found $critical_count dependency vulnerabilities"
|
||||||
jq '.vulnerabilities[] | "- \(.package_name) \(.installed_version): \(.vulnerability_id)"' safety-report.json
|
jq '.vulnerabilities[] | "- \(.package_name) \(.installed_version): \(.vulnerability_id)"' safety-report.json
|
||||||
else
|
else
|
||||||
echo "✅ No dependency vulnerabilities found"
|
echo "No dependency vulnerabilities found"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -78,86 +80,9 @@ jobs:
|
|||||||
if [ -f bandit-report.json ]; then
|
if [ -f bandit-report.json ]; then
|
||||||
high_severity=$(jq '.results[] | select(.issue_severity == "HIGH") | length' bandit-report.json 2>/dev/null | wc -l)
|
high_severity=$(jq '.results[] | select(.issue_severity == "HIGH") | length' bandit-report.json 2>/dev/null | wc -l)
|
||||||
if [ "$high_severity" -gt 0 ]; then
|
if [ "$high_severity" -gt 0 ]; then
|
||||||
echo "⚠️ Found $high_severity high-severity security issues"
|
echo "Found $high_severity high-severity security issues"
|
||||||
else
|
else
|
||||||
echo "✅ No high-severity security issues found"
|
echo "No high-severity security issues found"
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Docker image security scan
|
|
||||||
docker-security-scan:
|
|
||||||
name: Docker Security Scan
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Check GitHub token availability
|
|
||||||
run: |
|
|
||||||
if [ -z "${{ secrets.GH_TOKEN }}" ]; then
|
|
||||||
echo "⚠️ GH_TOKEN not configured. Trivy scans may fail due to rate limits."
|
|
||||||
echo "💡 To fix: Add GH_TOKEN secret in repository settings"
|
|
||||||
else
|
|
||||||
echo "✅ GH_TOKEN is configured"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Build Docker image for scanning
|
|
||||||
run: |
|
|
||||||
docker build -t ping-river-monitor:scan .
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
|
|
||||||
- name: Run Trivy vulnerability scanner
|
|
||||||
uses: aquasecurity/trivy-action@master
|
|
||||||
with:
|
|
||||||
image-ref: "ping-river-monitor:scan"
|
|
||||||
format: "json"
|
|
||||||
output: "trivy-report.json"
|
|
||||||
github-token: ${{ secrets.GH_TOKEN }}
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
continue-on-error: true
|
|
||||||
|
|
||||||
- name: Run Trivy filesystem scan
|
|
||||||
uses: aquasecurity/trivy-action@master
|
|
||||||
with:
|
|
||||||
scan-type: "fs"
|
|
||||||
scan-ref: "."
|
|
||||||
format: "json"
|
|
||||||
output: "trivy-fs-report.json"
|
|
||||||
github-token: ${{ secrets.GH_TOKEN }}
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
continue-on-error: true
|
|
||||||
|
|
||||||
- name: Upload Trivy reports
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
name: trivy-reports-${{ github.run_number }}
|
|
||||||
path: |
|
|
||||||
trivy-report.json
|
|
||||||
trivy-fs-report.json
|
|
||||||
|
|
||||||
- name: Check Trivy results
|
|
||||||
run: |
|
|
||||||
echo "🔍 Analyzing Docker security scan results..."
|
|
||||||
|
|
||||||
if [ -f trivy-report.json ]; then
|
|
||||||
critical_vulns=$(jq '.Results[]?.Vulnerabilities[]? | select(.Severity == "CRITICAL") | length' trivy-report.json 2>/dev/null | wc -l)
|
|
||||||
high_vulns=$(jq '.Results[]?.Vulnerabilities[]? | select(.Severity == "HIGH") | length' trivy-report.json 2>/dev/null | wc -l)
|
|
||||||
|
|
||||||
echo "Critical vulnerabilities: $critical_vulns"
|
|
||||||
echo "High vulnerabilities: $high_vulns"
|
|
||||||
|
|
||||||
if [ "$critical_vulns" -gt 0 ]; then
|
|
||||||
echo "❌ Critical vulnerabilities found in Docker image!"
|
|
||||||
exit 1
|
|
||||||
elif [ "$high_vulns" -gt 5 ]; then
|
|
||||||
echo "⚠️ Many high-severity vulnerabilities found"
|
|
||||||
else
|
|
||||||
echo "✅ Docker image security scan passed"
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -169,6 +94,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
@@ -183,7 +110,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Check licenses
|
- name: Check licenses
|
||||||
run: |
|
run: |
|
||||||
echo "📄 Checking dependency licenses..."
|
echo "Checking dependency licenses..."
|
||||||
pip-licenses --format=json --output-file=licenses.json
|
pip-licenses --format=json --output-file=licenses.json
|
||||||
pip-licenses --format=markdown --output-file=licenses.md
|
pip-licenses --format=markdown --output-file=licenses.md
|
||||||
|
|
||||||
@@ -192,11 +119,11 @@ jobs:
|
|||||||
|
|
||||||
for license in "${problematic_licenses[@]}"; do
|
for license in "${problematic_licenses[@]}"; do
|
||||||
if grep -i "$license" licenses.json; then
|
if grep -i "$license" licenses.json; then
|
||||||
echo "⚠️ Found potentially problematic license: $license"
|
echo "Found potentially problematic license: $license"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "✅ License check completed"
|
echo "License check completed"
|
||||||
|
|
||||||
- name: Upload license report
|
- name: Upload license report
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
@@ -214,6 +141,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
@@ -227,56 +156,15 @@ jobs:
|
|||||||
|
|
||||||
- name: Check for outdated packages
|
- name: Check for outdated packages
|
||||||
run: |
|
run: |
|
||||||
echo "📦 Checking for outdated packages..."
|
echo "Checking for outdated packages..."
|
||||||
pip install --root-user-action=ignore -r requirements.txt
|
pip install --root-user-action=ignore -r requirements.txt
|
||||||
pip list --outdated --format=json > outdated-packages.json || true
|
pip list --outdated --format=json > outdated-packages.json || true
|
||||||
|
|
||||||
if [ -s outdated-packages.json ]; then
|
if [ -s outdated-packages.json ]; then
|
||||||
echo "📋 Outdated packages found:"
|
echo "Outdated packages found:"
|
||||||
cat outdated-packages.json | jq -r '.[] | "- \(.name): \(.version) -> \(.latest_version)"'
|
cat outdated-packages.json | jq -r '.[] | "- \(.name): \(.version) -> \(.latest_version)"'
|
||||||
else
|
else
|
||||||
echo "✅ All packages are up to date"
|
echo "All packages are up to date"
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Create dependency update issue
|
|
||||||
if: github.event_name == 'schedule'
|
|
||||||
run: |
|
|
||||||
if [ -s outdated-packages.json ] && [ "$(cat outdated-packages.json)" != "[]" ]; then
|
|
||||||
echo "📝 Creating dependency update issue..."
|
|
||||||
|
|
||||||
# Create issue body
|
|
||||||
cat > issue-body.md << 'EOF'
|
|
||||||
## 📦 Dependency Updates Available
|
|
||||||
|
|
||||||
The following packages have updates available:
|
|
||||||
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cat outdated-packages.json | jq -r '.[] | "- **\(.name)**: \(.version) → \(.latest_version)"' >> issue-body.md
|
|
||||||
|
|
||||||
cat >> issue-body.md << 'EOF'
|
|
||||||
|
|
||||||
## 🔍 Security Impact
|
|
||||||
|
|
||||||
Please review each update for:
|
|
||||||
- Security fixes
|
|
||||||
- Breaking changes
|
|
||||||
- Compatibility issues
|
|
||||||
|
|
||||||
## ✅ Action Items
|
|
||||||
|
|
||||||
- [ ] Review changelog for each package
|
|
||||||
- [ ] Test updates in development environment
|
|
||||||
- [ ] Update requirements.txt
|
|
||||||
- [ ] Run full test suite
|
|
||||||
- [ ] Deploy to staging for validation
|
|
||||||
|
|
||||||
---
|
|
||||||
*This issue was automatically created by the security workflow.*
|
|
||||||
EOF
|
|
||||||
|
|
||||||
echo "Issue body created. In a real implementation, you would create a Gitea issue here."
|
|
||||||
cat issue-body.md
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Upload dependency reports
|
- name: Upload dependency reports
|
||||||
@@ -285,7 +173,6 @@ jobs:
|
|||||||
name: dependency-reports-${{ github.run_number }}
|
name: dependency-reports-${{ github.run_number }}
|
||||||
path: |
|
path: |
|
||||||
outdated-packages.json
|
outdated-packages.json
|
||||||
issue-body.md
|
|
||||||
|
|
||||||
# Code quality metrics
|
# Code quality metrics
|
||||||
code-quality:
|
code-quality:
|
||||||
@@ -295,6 +182,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
@@ -309,24 +198,24 @@ jobs:
|
|||||||
|
|
||||||
- name: Calculate code complexity
|
- name: Calculate code complexity
|
||||||
run: |
|
run: |
|
||||||
echo "📊 Calculating code complexity..."
|
echo "Calculating code complexity..."
|
||||||
radon cc src/ --json > complexity-report.json
|
radon cc src/ --json > complexity-report.json
|
||||||
radon mi src/ --json > maintainability-report.json
|
radon mi src/ --json > maintainability-report.json
|
||||||
|
|
||||||
echo "🔍 Complexity Summary:"
|
echo "Complexity Summary:"
|
||||||
radon cc src/ --average
|
radon cc src/ --average
|
||||||
|
|
||||||
echo "🔧 Maintainability Summary:"
|
echo "Maintainability Summary:"
|
||||||
radon mi src/
|
radon mi src/
|
||||||
|
|
||||||
- name: Find dead code
|
- name: Find dead code
|
||||||
run: |
|
run: |
|
||||||
echo "🧹 Checking for dead code..."
|
echo "Checking for dead code..."
|
||||||
vulture src/ --json > dead-code-report.json || true
|
vulture src/ --json > dead-code-report.json || true
|
||||||
|
|
||||||
- name: Check for code smells
|
- name: Check for code smells
|
||||||
run: |
|
run: |
|
||||||
echo "👃 Checking for code smells..."
|
echo "Checking for code smells..."
|
||||||
xenon --max-absolute B --max-modules A --max-average A src/ || true
|
xenon --max-absolute B --max-modules A --max-average A src/ || true
|
||||||
|
|
||||||
- name: Upload quality reports
|
- name: Upload quality reports
|
||||||
@@ -342,7 +231,7 @@ jobs:
|
|||||||
security-summary:
|
security-summary:
|
||||||
name: Security Summary
|
name: Security Summary
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [dependency-scan, docker-security-scan, license-check, code-quality]
|
needs: [dependency-scan, license-check, code-quality]
|
||||||
if: always()
|
if: always()
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -351,51 +240,47 @@ jobs:
|
|||||||
|
|
||||||
- name: Generate security summary
|
- name: Generate security summary
|
||||||
run: |
|
run: |
|
||||||
echo "# 🔒 Security Scan Summary" > security-summary.md
|
echo "# Security Scan Summary" > security-summary.md
|
||||||
echo "" >> security-summary.md
|
echo "" >> security-summary.md
|
||||||
echo "**Scan Date:** $(date -u)" >> security-summary.md
|
echo "**Scan Date:** $(date -u)" >> security-summary.md
|
||||||
echo "**Repository:** ${{ github.repository }}" >> security-summary.md
|
echo "**Repository:** ${{ github.repository }}" >> security-summary.md
|
||||||
echo "**Commit:** ${{ github.sha }}" >> security-summary.md
|
echo "**Commit:** ${{ github.sha }}" >> security-summary.md
|
||||||
echo "" >> security-summary.md
|
echo "" >> security-summary.md
|
||||||
|
|
||||||
echo "## 📊 Results" >> security-summary.md
|
echo "## Results" >> security-summary.md
|
||||||
echo "" >> security-summary.md
|
echo "" >> security-summary.md
|
||||||
|
|
||||||
# Dependency scan results
|
# Dependency scan results
|
||||||
if [ -f security-reports-*/safety-report.json ]; then
|
if [ -f security-reports-*/safety-report.json ]; then
|
||||||
vuln_count=$(jq '.vulnerabilities | length' security-reports-*/safety-report.json 2>/dev/null || echo "0")
|
vuln_count=$(jq '.vulnerabilities | length' security-reports-*/safety-report.json 2>/dev/null || echo "0")
|
||||||
if [ "$vuln_count" -eq 0 ]; then
|
if [ "$vuln_count" -eq 0 ]; then
|
||||||
echo "- ✅ **Dependency Scan**: No vulnerabilities found" >> security-summary.md
|
echo "- Dependency Scan: No vulnerabilities found" >> security-summary.md
|
||||||
else
|
else
|
||||||
echo "- ⚠️ **Dependency Scan**: $vuln_count vulnerabilities found" >> security-summary.md
|
echo "- Dependency Scan: $vuln_count vulnerabilities found" >> security-summary.md
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "- ❓ **Dependency Scan**: Results not available" >> security-summary.md
|
echo "- Dependency Scan: Results not available" >> security-summary.md
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Docker scan results
|
# Docker scan results (removed Trivy)
|
||||||
if [ -f trivy-reports-*/trivy-report.json ]; then
|
echo "- Docker Scan: Skipped (Trivy removed)" >> security-summary.md
|
||||||
echo "- ✅ **Docker Scan**: Completed" >> security-summary.md
|
|
||||||
else
|
|
||||||
echo "- ❓ **Docker Scan**: Results not available" >> security-summary.md
|
|
||||||
fi
|
|
||||||
|
|
||||||
# License check results
|
# License check results
|
||||||
if [ -f license-report-*/licenses.json ]; then
|
if [ -f license-report-*/licenses.json ]; then
|
||||||
echo "- ✅ **License Check**: Completed" >> security-summary.md
|
echo "- License Check: Completed" >> security-summary.md
|
||||||
else
|
else
|
||||||
echo "- ❓ **License Check**: Results not available" >> security-summary.md
|
echo "- License Check: Results not available" >> security-summary.md
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Code quality results
|
# Code quality results
|
||||||
if [ -f code-quality-reports-*/complexity-report.json ]; then
|
if [ -f code-quality-reports-*/complexity-report.json ]; then
|
||||||
echo "- ✅ **Code Quality**: Analyzed" >> security-summary.md
|
echo "- Code Quality: Analyzed" >> security-summary.md
|
||||||
else
|
else
|
||||||
echo "- ❓ **Code Quality**: Results not available" >> security-summary.md
|
echo "- Code Quality: Results not available" >> security-summary.md
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "" >> security-summary.md
|
echo "" >> security-summary.md
|
||||||
echo "## 🔗 Detailed Reports" >> security-summary.md
|
echo "## Detailed Reports" >> security-summary.md
|
||||||
echo "" >> security-summary.md
|
echo "" >> security-summary.md
|
||||||
echo "Detailed reports are available in the workflow artifacts." >> security-summary.md
|
echo "Detailed reports are available in the workflow artifacts." >> security-summary.md
|
||||||
|
|
||||||
|
@@ -259,7 +259,7 @@ make health-check
|
|||||||
|
|
||||||
**Deployment Date**: ___________
|
**Deployment Date**: ___________
|
||||||
**Deployed By**: ___________
|
**Deployed By**: ___________
|
||||||
**Version**: v3.1.1
|
**Version**: v3.1.3
|
||||||
**Environment**: ___________
|
**Environment**: ___________
|
||||||
|
|
||||||
**Sign-off**:
|
**Sign-off**:
|
||||||
|
@@ -222,12 +222,12 @@ Your repository is now equipped with:
|
|||||||
2. **Configure deployment environments** (staging/production)
|
2. **Configure deployment environments** (staging/production)
|
||||||
3. **Set up monitoring dashboards** for workflow metrics
|
3. **Set up monitoring dashboards** for workflow metrics
|
||||||
4. **Configure notifications** for team collaboration
|
4. **Configure notifications** for team collaboration
|
||||||
5. **Create your first release** with `git tag v3.1.1`
|
5. **Create your first release** with `git tag v3.1.3`
|
||||||
|
|
||||||
Your **Northern Thailand Ping River Monitor** is now ready for professional development and deployment! 🎊
|
Your **Northern Thailand Ping River Monitor** is now ready for professional development and deployment! 🎊
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Workflow Version**: v3.1.1
|
**Workflow Version**: v3.1.3
|
||||||
**Setup Date**: 2025-08-12
|
**Setup Date**: 2025-08-12
|
||||||
**Repository**: https://git.b4l.co.th/grabowski/Northern-Thailand-Ping-River-Monitor
|
**Repository**: https://git.b4l.co.th/grabowski/Northern-Thailand-Ping-River-Monitor
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
A comprehensive real-time water level monitoring system for the Ping River Basin in Northern Thailand, covering Royal Irrigation Department (RID) stations from Chiang Dao to Nakhon Sawan with advanced data collection, storage, and visualization capabilities.
|
A comprehensive real-time water level monitoring system for the Ping River Basin in Northern Thailand, covering Royal Irrigation Department (RID) stations from Chiang Dao to Nakhon Sawan with advanced data collection, storage, and visualization capabilities.
|
||||||
|
|
||||||
[](https://git.b4l.co.th/B4L/Northern-Thailand-Ping-River-Monitor/actions) [](https://git.b4l.co.th/B4L/Northern-Thailand-Ping-River-Monitor/actions) [](https://git.b4l.co.th/B4L/Northern-Thailand-Ping-River-Monitor/actions) [](https://python.org) [](https://fastapi.tiangolo.com) [](https://docker.com) [](LICENSE) [](https://git.b4l.co.th/B4L/Northern-Thailand-Ping-River-Monitor/releases)
|
[](https://git.b4l.co.th/B4L/Northern-Thailand-Ping-River-Monitor/actions) [](https://git.b4l.co.th/B4L/Northern-Thailand-Ping-River-Monitor/actions) [](https://git.b4l.co.th/B4L/Northern-Thailand-Ping-River-Monitor/actions) [](https://python.org) [](https://fastapi.tiangolo.com) [](https://docker.com) [](LICENSE) [](https://git.b4l.co.th/B4L/Northern-Thailand-Ping-River-Monitor/releases)
|
||||||
|
|
||||||
## 🌟 Features
|
## 🌟 Features
|
||||||
|
|
||||||
|
@@ -297,6 +297,6 @@ make validate-workflows
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Workflow Version**: v3.1.1
|
**Workflow Version**: v3.1.3
|
||||||
**Last Updated**: 2025-08-12
|
**Last Updated**: 2025-08-12
|
||||||
**Maintained By**: Ping River Monitor Team
|
**Maintained By**: Ping River Monitor Team
|
@@ -29,7 +29,7 @@ def main():
|
|||||||
"FastAPI": generate_badge_url("FastAPI", "0.104%2B", "green"),
|
"FastAPI": generate_badge_url("FastAPI", "0.104%2B", "green"),
|
||||||
"Docker": generate_badge_url("Docker", "Ready", "blue"),
|
"Docker": generate_badge_url("Docker", "Ready", "blue"),
|
||||||
"License": generate_badge_url("License", "MIT", "green"),
|
"License": generate_badge_url("License", "MIT", "green"),
|
||||||
"Version": generate_badge_url("Version", "v3.1.1", "blue"),
|
"Version": generate_badge_url("Version", "v3.1.3", "blue"),
|
||||||
}
|
}
|
||||||
|
|
||||||
print("# Status Badges")
|
print("# Status Badges")
|
||||||
|
@@ -13,7 +13,7 @@ REM Add all files
|
|||||||
git add .
|
git add .
|
||||||
|
|
||||||
REM Initial commit
|
REM Initial commit
|
||||||
git commit -m "Initial commit: Northern Thailand Ping River Monitor v3.1.1
|
git commit -m "Initial commit: Northern Thailand Ping River Monitor v3.1.3
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
- Real-time water level monitoring for Ping River Basin
|
- Real-time water level monitoring for Ping River Basin
|
||||||
|
@@ -66,7 +66,7 @@ fi
|
|||||||
git add .
|
git add .
|
||||||
|
|
||||||
# Initial commit
|
# Initial commit
|
||||||
git commit -m "Initial commit: Northern Thailand Ping River Monitor v3.1.1
|
git commit -m "Initial commit: Northern Thailand Ping River Monitor v3.1.3
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
- Real-time water level monitoring for Ping River Basin
|
- Real-time water level monitoring for Ping River Basin
|
||||||
|
16
setup.py
16
setup.py
@@ -11,8 +11,18 @@ with open("README.md", "r", encoding="utf-8") as fh:
|
|||||||
long_description = fh.read()
|
long_description = fh.read()
|
||||||
|
|
||||||
# Read requirements
|
# Read requirements
|
||||||
with open("requirements.txt", "r", encoding="utf-8") as fh:
|
try:
|
||||||
requirements = [line.strip() for line in fh if line.strip() and not line.startswith("#")]
|
with open("requirements.txt", "r", encoding="utf-8") as fh:
|
||||||
|
requirements = [line.strip() for line in fh if line.strip() and not line.startswith("#")]
|
||||||
|
except FileNotFoundError:
|
||||||
|
# Fallback to minimal requirements if file not found
|
||||||
|
requirements = [
|
||||||
|
"requests>=2.31.0",
|
||||||
|
"schedule>=1.2.0",
|
||||||
|
"pandas>=2.1.0",
|
||||||
|
"fastapi>=0.104.0",
|
||||||
|
"uvicorn>=0.24.0",
|
||||||
|
]
|
||||||
|
|
||||||
# Extract core requirements (exclude dev dependencies)
|
# Extract core requirements (exclude dev dependencies)
|
||||||
core_requirements = []
|
core_requirements = []
|
||||||
@@ -22,7 +32,7 @@ for req in requirements:
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="northern-thailand-ping-river-monitor",
|
name="northern-thailand-ping-river-monitor",
|
||||||
version="3.1.1",
|
version="3.1.3",
|
||||||
author="Ping River Monitor Team",
|
author="Ping River Monitor Team",
|
||||||
author_email="contact@example.com",
|
author_email="contact@example.com",
|
||||||
description="Real-time water level monitoring system for the Ping River Basin in Northern Thailand",
|
description="Real-time water level monitoring system for the Ping River Basin in Northern Thailand",
|
||||||
|
@@ -6,7 +6,7 @@ A comprehensive real-time water level monitoring system for the Ping River Basin
|
|||||||
in Northern Thailand, covering Royal Irrigation Department (RID) stations.
|
in Northern Thailand, covering Royal Irrigation Department (RID) stations.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "3.1.1"
|
__version__ = "3.1.3"
|
||||||
__author__ = "Ping River Monitor Team"
|
__author__ = "Ping River Monitor Team"
|
||||||
__description__ = "Northern Thailand Ping River Monitoring System"
|
__description__ = "Northern Thailand Ping River Monitoring System"
|
||||||
|
|
||||||
|
@@ -297,7 +297,7 @@ Examples:
|
|||||||
)
|
)
|
||||||
|
|
||||||
logger.info("🏔️ Northern Thailand Ping River Monitor starting...")
|
logger.info("🏔️ Northern Thailand Ping River Monitor starting...")
|
||||||
logger.info(f"Version: 3.1.1")
|
logger.info(f"Version: 3.1.3")
|
||||||
logger.info(f"Log level: {args.log_level}")
|
logger.info(f"Log level: {args.log_level}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@@ -143,7 +143,7 @@ async def lifespan(app: FastAPI):
|
|||||||
app = FastAPI(
|
app = FastAPI(
|
||||||
title="Northern Thailand Ping River Monitor API",
|
title="Northern Thailand Ping River Monitor API",
|
||||||
description="Real-time water level monitoring system for Northern Thailand's Ping River Basin stations",
|
description="Real-time water level monitoring system for Northern Thailand's Ping River Basin stations",
|
||||||
version="3.1.1",
|
version="3.1.3",
|
||||||
lifespan=lifespan
|
lifespan=lifespan
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -165,7 +165,7 @@ def test_logging():
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Run all tests"""
|
"""Run all tests"""
|
||||||
print("🧪 Running integration tests for Northern Thailand Ping River Monitor v3.1.1")
|
print("🧪 Running integration tests for Northern Thailand Ping River Monitor v3.1.3")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
tests = [
|
tests = [
|
||||||
|
Reference in New Issue
Block a user