diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 9af7cdf..441432d 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -3,16 +3,16 @@ name: Release - Northern Thailand Ping River Monitor on: push: tags: - - 'v*.*.*' + - "v*.*.*" workflow_dispatch: inputs: version: - description: 'Release version (e.g., v3.1.3)' + description: "Release version (e.g., v3.1.3)" required: true type: string env: - PYTHON_VERSION: '3.11' + PYTHON_VERSION: "3.11" REGISTRY: git.b4l.co.th IMAGE_NAME: b4l/northern-thailand-ping-river-monitor # GitHub token for better rate limits and authentication @@ -25,44 +25,44 @@ jobs: runs-on: ubuntu-latest outputs: version: ${{ steps.version.outputs.version }} - + steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITEA_TOKEN }} - fetch-depth: 0 - - - name: Get version - id: version - run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT - else - echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT - fi - - - name: Generate changelog - id: changelog - run: | - # Generate changelog from git commits - echo "## Changes" > CHANGELOG.md - git log --pretty=format:"- %s" $(git describe --tags --abbrev=0 HEAD^)..HEAD >> CHANGELOG.md || echo "- Initial release" >> CHANGELOG.md - echo "" >> CHANGELOG.md - echo "## Docker Images" >> CHANGELOG.md - echo "- \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }}\`" >> CHANGELOG.md - echo "- \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest\`" >> CHANGELOG.md - - - name: Create Release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }} - with: - tag_name: ${{ steps.version.outputs.version }} - release_name: Northern Thailand Ping River Monitor ${{ steps.version.outputs.version }} - body_path: CHANGELOG.md - draft: false - prerelease: false + - name: Checkout code + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITEA_TOKEN }} + fetch-depth: 0 + + - name: Get version + id: version + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT + else + echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + fi + + - name: Generate changelog + id: changelog + run: | + # Generate changelog from git commits + echo "## Changes" > CHANGELOG.md + git log --pretty=format:"- %s" $(git describe --tags --abbrev=0 HEAD^)..HEAD >> CHANGELOG.md || echo "- Initial release" >> CHANGELOG.md + echo "" >> CHANGELOG.md + echo "## Docker Images" >> CHANGELOG.md + echo "- \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }}\`" >> CHANGELOG.md + echo "- \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest\`" >> CHANGELOG.md + + - name: Create Release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }} + with: + tag_name: ${{ steps.version.outputs.version }} + release_name: Northern Thailand Ping River Monitor ${{ steps.version.outputs.version }} + body_path: CHANGELOG.md + draft: false + prerelease: false # Build and test for release test-release: @@ -71,97 +71,95 @@ jobs: needs: create-release strategy: matrix: - python-version: ['3.9', '3.10', '3.11', '3.12'] - + python-version: ["3.9", "3.10", "3.11", "3.12"] + steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITEA_TOKEN }} - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - - name: Install dependencies - run: | - python -m pip install --upgrade pip --root-user-action=ignore - pip install --root-user-action=ignore -r requirements.txt - pip install --root-user-action=ignore -r requirements-dev.txt - - - name: Run full test suite - run: | - python tests/test_integration.py - python tests/test_station_management.py - python run.py --test - - - name: Build Python package - run: | - pip install --root-user-action=ignore build - python -m build - - - name: Upload Python package - uses: actions/upload-artifact@v3 - with: - name: python-package-${{ matrix.python-version }} - path: dist/ + - name: Checkout code + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITEA_TOKEN }} + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip --root-user-action=ignore + pip install --root-user-action=ignore -r requirements.txt + pip install --root-user-action=ignore -r requirements-dev.txt + + - name: Run full test suite + run: | + python tests/test_integration.py + python tests/test_station_management.py + python run.py --test + + - name: Build Python package + run: | + pip install --root-user-action=ignore build + python -m build + + - name: Upload Python package + uses: actions/upload-artifact@v3 + with: + name: python-package-${{ matrix.python-version }} + path: dist/ # Build release Docker images build-release: name: Build Release Images runs-on: ubuntu-latest needs: [create-release, test-release] - + steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITEA_TOKEN }} - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - 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: Build and push release images - uses: docker/build-push-action@v5 - with: - context: . - platforms: linux/amd64,linux/arm64 - push: true - tags: | - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-release.outputs.version }} - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest - labels: | - org.opencontainers.image.title=Northern Thailand Ping River Monitor - org.opencontainers.image.description=Real-time water level monitoring for Ping River Basin - org.opencontainers.image.version=${{ needs.create-release.outputs.version }} - org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} - org.opencontainers.image.revision=${{ github.sha }} - cache-from: type=gha - cache-to: type=gha,mode=max - env: - GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }} + - name: Checkout code + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITEA_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - 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: Build and push release images + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-release.outputs.version }} + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + labels: | + org.opencontainers.image.title=Northern Thailand Ping River Monitor + org.opencontainers.image.description=Real-time water level monitoring for Ping River Basin + org.opencontainers.image.version=${{ needs.create-release.outputs.version }} + org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} + org.opencontainers.image.revision=${{ github.sha }} + cache-from: type=gha + cache-to: type=gha,mode=max + env: + GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }} # Security scan for release security-scan: name: Security Scan runs-on: ubuntu-latest needs: build-release - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITEA_TOKEN}} - + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITEA_TOKEN}} # Test release deployment locally deploy-release: @@ -171,85 +169,90 @@ jobs: environment: name: testing url: http://localhost:8080 - + steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITEA_TOKEN }} - - - 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: | - echo "๐Ÿš€ Testing ${{ needs.create-release.outputs.version }} deployment locally..." - - # Pull the built image - docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-release.outputs.version }} - - # 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 - run: | - echo "โณ Waiting for application to start..." - sleep 30 - - echo "๐Ÿ” Running health checks against local container..." - - # 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 - - # 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: | - 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 "Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-release.outputs.version }}" - echo "Status: Container tested successfully" - echo "Ready for production deployment" + - name: Checkout code + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITEA_TOKEN }} + - 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: | + echo "๐Ÿš€ Testing ${{ needs.create-release.outputs.version }} deployment locally..." + + # Pull the built image + docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-release.outputs.version }} + + # 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 + run: | + echo "โณ Waiting for application to start..." + sleep 30 + + echo "๐Ÿ” Running health checks against local container..." + + # Check if container is running + docker ps | grep ping-river-monitor-test || echo "โš ๏ธ Container not found in docker ps" + + # Check container logs for any startup issues + echo "๐Ÿ“‹ Recent container logs:" + docker logs --tail 10 ping-river-monitor-test || true + + # Wait for the application to be ready + for i in {1..12}; do + if curl -f http://127.0.0.1:8080/health; then + echo "โœ… Health endpoint responding" + break + else + echo "โณ Waiting for health endpoint... (attempt $i/12)" + sleep 10 + fi + done + + # Test API endpoints + echo "๐Ÿงช Testing API endpoints..." + curl -f http://127.0.0.1:8080/health || exit 1 + curl -f http://127.0.0.1:8080/docs || exit 1 + curl -f http://127.0.0.1:8080/stations || exit 1 + curl -f http://127.0.0.1:8080/metrics || exit 1 + + echo "โœ… All health checks passed!" + + - name: Container logs and cleanup + if: always() + run: | + 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 "Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-release.outputs.version }}" + echo "Status: Container tested successfully" + echo "Ready for production deployment" # Notify stakeholders notify: @@ -257,28 +260,28 @@ jobs: runs-on: ubuntu-latest needs: [create-release, deploy-release] if: always() - + steps: - - name: Notify success - if: needs.deploy-release.result == 'success' - run: | - echo "๐ŸŽ‰ Release ${{ needs.create-release.outputs.version }} tested successfully!" - echo "๐Ÿงช Local Test: Passed all health checks" - echo "๏ฟฝ GDocker Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-release.outputs.version }}" - echo "โœ… Ready for production deployment" - - # Add notification to Slack, Discord, email, etc. - # curl -X POST -H 'Content-type: application/json' \ - # --data '{"text":"๐ŸŽ‰ Northern Thailand Ping River Monitor ${{ needs.create-release.outputs.version }} tested and ready for deployment!"}' \ - # ${{ secrets.SLACK_WEBHOOK_URL }} - - - name: Notify failure - if: needs.deploy-release.result == 'failure' - run: | - echo "โŒ Release ${{ needs.create-release.outputs.version }} testing failed!" - echo "Please check the logs and fix issues before production deployment." - - # Add failure notification - # curl -X POST -H 'Content-type: application/json' \ - # --data '{"text":"โŒ Northern Thailand Ping River Monitor ${{ needs.create-release.outputs.version }} testing failed!"}' \ - # ${{ secrets.SLACK_WEBHOOK_URL }} \ No newline at end of file + - name: Notify success + if: needs.deploy-release.result == 'success' + run: | + echo "๐ŸŽ‰ Release ${{ needs.create-release.outputs.version }} tested successfully!" + echo "๐Ÿงช Local Test: Passed all health checks" + echo "๏ฟฝ GDocker Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.create-release.outputs.version }}" + echo "โœ… Ready for production deployment" + + # Add notification to Slack, Discord, email, etc. + # curl -X POST -H 'Content-type: application/json' \ + # --data '{"text":"๐ŸŽ‰ Northern Thailand Ping River Monitor ${{ needs.create-release.outputs.version }} tested and ready for deployment!"}' \ + # ${{ secrets.SLACK_WEBHOOK_URL }} + + - name: Notify failure + if: needs.deploy-release.result == 'failure' + run: | + echo "โŒ Release ${{ needs.create-release.outputs.version }} testing failed!" + echo "Please check the logs and fix issues before production deployment." + + # Add failure notification + # curl -X POST -H 'Content-type: application/json' \ + # --data '{"text":"โŒ Northern Thailand Ping River Monitor ${{ needs.create-release.outputs.version }} testing failed!"}' \ + # ${{ secrets.SLACK_WEBHOOK_URL }}