chore: bump eafw_geomanager_web — migration 0034 universal scope helper #234
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # EAFW FloodWatch - Build & Deploy to Staging | |
| # Triggers on push to eafw branch | |
| # Only builds images when their source files change | |
| # Deploy is modular: only pulls + restarts services that were rebuilt | |
| name: Build & Deploy to Staging | |
| on: | |
| push: | |
| branches: | |
| - eafw | |
| workflow_dispatch: | |
| inputs: | |
| force_build: | |
| description: 'Force rebuild all images' | |
| type: boolean | |
| default: false | |
| deploy_only: | |
| description: 'Skip build, deploy existing images by SHA' | |
| type: string | |
| default: '' | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_PREFIX: ghcr.io/${{ github.repository_owner }} | |
| jobs: | |
| detect-changes: | |
| name: Detect Changes | |
| runs-on: ubuntu-latest | |
| outputs: | |
| cms: ${{ steps.changes.outputs.cms }} | |
| mapviewer: ${{ steps.changes.outputs.mapviewer }} | |
| mapserver: ${{ steps.changes.outputs.mapserver }} | |
| mapcache: ${{ steps.changes.outputs.mapcache }} | |
| jobs: ${{ steps.changes.outputs.jobs }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 2 | |
| submodules: false | |
| - name: Check for changes | |
| id: changes | |
| run: | | |
| CHANGED=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || echo "") | |
| echo "Changed files: $CHANGED" | |
| # Match both regular file paths (eafw_geomanager_web/...) and bare | |
| # submodule pointer changes (eafw_geomanager_web with no trailing slash) | |
| if echo "$CHANGED" | grep -qE "^(eafw_geomanager_web|eafw_geomanager|eafw_georeport)(/|$)|^docker/cms/"; then | |
| echo "cms=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "cms=false" >> $GITHUB_OUTPUT | |
| fi | |
| if echo "$CHANGED" | grep -qE "^eafw_geomapviewer(/|$)|^docker/mapviewer/"; then | |
| echo "mapviewer=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "mapviewer=false" >> $GITHUB_OUTPUT | |
| fi | |
| if echo "$CHANGED" | grep -qE "^docker/mapserver/|^config/mapfiles/"; then | |
| echo "mapserver=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "mapserver=false" >> $GITHUB_OUTPUT | |
| fi | |
| if echo "$CHANGED" | grep -qE "^docker/mapcache/|^config/mapcache/"; then | |
| echo "mapcache=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "mapcache=false" >> $GITHUB_OUTPUT | |
| fi | |
| if echo "$CHANGED" | grep -qE "^docker/jobs/|^eafw_jobs/"; then | |
| echo "jobs=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "jobs=false" >> $GITHUB_OUTPUT | |
| fi | |
| build-cms: | |
| name: Build CMS | |
| runs-on: ubuntu-latest | |
| needs: detect-changes | |
| if: needs.detect-changes.outputs.cms == 'true' || github.event.inputs.force_build == 'true' | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: docker/setup-buildx-action@v3 | |
| - uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push CMS | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| file: ./docker/cms/Dockerfile | |
| push: true | |
| tags: | | |
| ${{ env.IMAGE_PREFIX }}/eafw-cms:latest | |
| ${{ env.IMAGE_PREFIX }}/eafw-cms:${{ github.sha }} | |
| build-args: | | |
| GH_TOKEN=${{ secrets.GH_PAT }} | |
| CACHEBUST=${{ github.run_id }} | |
| no-cache: true | |
| build-mapviewer: | |
| name: Build Mapviewer | |
| runs-on: ubuntu-latest | |
| needs: detect-changes | |
| if: needs.detect-changes.outputs.mapviewer == 'true' || github.event.inputs.force_build == 'true' | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| token: ${{ secrets.GH_PAT }} | |
| - uses: docker/setup-buildx-action@v3 | |
| - uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push Mapviewer | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: ./eafw_geomapviewer | |
| file: ./docker/mapviewer/Dockerfile | |
| push: true | |
| tags: | | |
| ${{ env.IMAGE_PREFIX }}/eafw-mapviewer:latest | |
| ${{ env.IMAGE_PREFIX }}/eafw-mapviewer:${{ github.sha }} | |
| build-args: | | |
| CMS_API=/api | |
| BASE_PATH=/ | |
| ASSET_PREFIX= | |
| ADMIN_BOUNDARY_API=/pg/tileserv/ | |
| ANALYTICS_PROPERTY_ID=${{ secrets.STAGING_ANALYTICS_PROPERTY_ID }} | |
| NEXT_TELEMETRY_DISABLED=1 | |
| build-mapserver: | |
| name: Build Mapserver | |
| runs-on: ubuntu-latest | |
| needs: detect-changes | |
| if: needs.detect-changes.outputs.mapserver == 'true' || github.event.inputs.force_build == 'true' | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: docker/setup-buildx-action@v3 | |
| - uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push Mapserver | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| file: ./docker/mapserver/Dockerfile | |
| push: true | |
| tags: | | |
| ${{ env.IMAGE_PREFIX }}/eafw-mapserver:latest | |
| ${{ env.IMAGE_PREFIX }}/eafw-mapserver:${{ github.sha }} | |
| build-mapcache: | |
| name: Build Mapcache | |
| runs-on: ubuntu-latest | |
| needs: detect-changes | |
| if: needs.detect-changes.outputs.mapcache == 'true' || github.event.inputs.force_build == 'true' | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: docker/setup-buildx-action@v3 | |
| - uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push Mapcache | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| file: ./docker/mapcache/Dockerfile | |
| push: true | |
| tags: | | |
| ${{ env.IMAGE_PREFIX }}/eafw-mapcache:latest | |
| ${{ env.IMAGE_PREFIX }}/eafw-mapcache:${{ github.sha }} | |
| build-jobs: | |
| name: Build Jobs | |
| runs-on: ubuntu-latest | |
| needs: detect-changes | |
| if: needs.detect-changes.outputs.jobs == 'true' || github.event.inputs.force_build == 'true' | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: docker/setup-buildx-action@v3 | |
| - uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push Jobs | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| file: ./docker/jobs/Dockerfile | |
| push: true | |
| tags: | | |
| ${{ env.IMAGE_PREFIX }}/eafw-jobs:latest | |
| ${{ env.IMAGE_PREFIX }}/eafw-jobs:${{ github.sha }} | |
| deploy: | |
| name: Deploy to Staging | |
| runs-on: ubuntu-latest | |
| needs: [detect-changes, build-cms, build-mapviewer, build-mapserver, build-mapcache, build-jobs] | |
| if: always() && !cancelled() | |
| environment: staging | |
| steps: | |
| - name: Determine which services to deploy | |
| id: services | |
| run: | | |
| SERVICES="" | |
| IMAGES="" | |
| SHA="${{ github.sha }}" | |
| PREFIX="${{ env.IMAGE_PREFIX }}" | |
| FORCE="${{ github.event.inputs.force_build }}" | |
| # A service needs deploy if it was rebuilt (job succeeded) | |
| # or if force_build was requested | |
| if [ "${{ needs.build-cms.result }}" = "success" ] || [ "$FORCE" = "true" ]; then | |
| SERVICES="$SERVICES cms" | |
| IMAGES="$IMAGES eafw-cms:$SHA" | |
| fi | |
| if [ "${{ needs.build-mapviewer.result }}" = "success" ] || [ "$FORCE" = "true" ]; then | |
| SERVICES="$SERVICES mapviewer" | |
| IMAGES="$IMAGES eafw-mapviewer:$SHA" | |
| fi | |
| if [ "${{ needs.build-mapserver.result }}" = "success" ] || [ "$FORCE" = "true" ]; then | |
| SERVICES="$SERVICES mapserver" | |
| IMAGES="$IMAGES eafw-mapserver:$SHA" | |
| fi | |
| if [ "${{ needs.build-mapcache.result }}" = "success" ] || [ "$FORCE" = "true" ]; then | |
| SERVICES="$SERVICES mapcache" | |
| IMAGES="$IMAGES eafw-mapcache:$SHA" | |
| fi | |
| if [ "${{ needs.build-jobs.result }}" = "success" ] || [ "$FORCE" = "true" ]; then | |
| SERVICES="$SERVICES jobs" | |
| IMAGES="$IMAGES eafw-jobs:$SHA" | |
| fi | |
| SERVICES=$(echo "$SERVICES" | xargs) | |
| IMAGES=$(echo "$IMAGES" | xargs) | |
| echo "services=$SERVICES" >> $GITHUB_OUTPUT | |
| echo "images=$IMAGES" >> $GITHUB_OUTPUT | |
| echo "sha=$SHA" >> $GITHUB_OUTPUT | |
| echo "Will deploy: $SERVICES" | |
| echo "Images: $IMAGES" | |
| - name: Deploy to staging server | |
| uses: appleboy/ssh-action@v1.0.3 | |
| env: | |
| GH_TOKEN: ${{ secrets.GH_PAT }} | |
| DB_PASSWORD: ${{ secrets.DB_PASSWORD }} | |
| DJANGO_SECRET_KEY: ${{ secrets.DJANGO_SECRET_KEY }} | |
| FLOODPROOFS_SFTP_HOST: ${{ secrets.FLOODPROOFS_SFTP_HOST }} | |
| FLOODPROOFS_SFTP_USER: ${{ secrets.FLOODPROOFS_SFTP_USER }} | |
| FLOODPROOFS_SFTP_PASSWORD: ${{ secrets.FLOODPROOFS_SFTP_PASSWORD }} | |
| WRF_FTP_HOST: ${{ secrets.WRF_FTP_HOST }} | |
| WRF_FTP_USER: ${{ secrets.WRF_FTP_USER }} | |
| WRF_FTP_PASSWORD: ${{ secrets.WRF_FTP_PASSWORD }} | |
| FLOODS_API_KEY: ${{ secrets.FLOODS_API_KEY }} | |
| SMTP_EMAIL_HOST: ${{ secrets.SMTP_EMAIL_HOST }} | |
| SMTP_EMAIL_HOST_USER: ${{ secrets.SMTP_EMAIL_HOST_USER }} | |
| SMTP_EMAIL_HOST_PASSWORD: ${{ secrets.SMTP_EMAIL_HOST_PASSWORD }} | |
| DEPLOY_SERVICES: ${{ steps.services.outputs.services }} | |
| DEPLOY_IMAGES: ${{ steps.services.outputs.images }} | |
| DEPLOY_SHA: ${{ steps.services.outputs.sha }} | |
| with: | |
| host: ${{ secrets.DEPLOY_HOST }} | |
| username: ${{ secrets.DEPLOY_USER }} | |
| key: ${{ secrets.SSH_KEY }} | |
| port: 22 | |
| command_timeout: 60m | |
| envs: GH_TOKEN,DB_PASSWORD,DJANGO_SECRET_KEY,FLOODPROOFS_SFTP_HOST,FLOODPROOFS_SFTP_USER,FLOODPROOFS_SFTP_PASSWORD,WRF_FTP_HOST,WRF_FTP_USER,WRF_FTP_PASSWORD,FLOODS_API_KEY,SMTP_EMAIL_HOST,SMTP_EMAIL_HOST_USER,SMTP_EMAIL_HOST_PASSWORD,DEPLOY_SERVICES,DEPLOY_IMAGES,DEPLOY_SHA | |
| script: | | |
| set -e | |
| cd ~ | |
| echo "=========================================" | |
| echo " STAGING DEPLOYMENT" | |
| echo " $(date '+%Y-%m-%d %H:%M:%S')" | |
| echo " Services: ${DEPLOY_SERVICES:-none}" | |
| echo " SHA: ${DEPLOY_SHA}" | |
| echo "=========================================" | |
| # Login to GHCR | |
| echo ${GH_TOKEN} | docker login ghcr.io -u icpac-igad --password-stdin | |
| # Safe repo update — submodules are private repos under icpac-igad, | |
| # so configure a per-user insteadOf rewrite that injects GH_TOKEN | |
| # for any github.com URL the submodule machinery touches. | |
| git config --global url."https://${GH_TOKEN}@github.com/".insteadOf "https://github.com/" | |
| REPO_DIR=~/projects/flood_watch_system | |
| if [ -d "$REPO_DIR/.git" ]; then | |
| cd $REPO_DIR | |
| git fetch origin | |
| git reset --hard origin/eafw | |
| else | |
| mkdir -p ~/projects | |
| git clone -b eafw https://${GH_TOKEN}@github.com/icpac-igad/flood_watch_system.git $REPO_DIR | |
| cd $REPO_DIR | |
| fi | |
| # One-time aside: legacy tracked directories from before the | |
| # submodule split linger on disk after a git reset --hard, blocking | |
| # the fresh submodule clone. Move (don't delete) anything that | |
| # isn't already a git checkout. Renaming the directory only needs | |
| # write access on the *parent*, so root-owned children inside the | |
| # legacy dir are preserved untouched in the .legacy backup. | |
| TS=$(date +%Y%m%d_%H%M%S) | |
| for sub in eafw_geomanager eafw_geomanager_web eafw_geomapviewer eafw_georeport; do | |
| if [ -d "$sub" ] && [ ! -e "$sub/.git" ]; then | |
| mv "$sub" "${sub}.legacy.${TS}" | |
| echo " moved aside: $sub -> ${sub}.legacy.${TS}" | |
| fi | |
| done | |
| # Sync + init/update every submodule to the SHA committed by the parent | |
| git submodule sync --recursive | |
| git submodule update --init --recursive --force | |
| echo "Git SHA: $(git rev-parse --short HEAD)" | |
| git submodule status | |
| # Smart .env — create from template only on first deploy | |
| if [ ! -f .env ]; then | |
| cp .env.example .env | |
| echo "FIRST DEPLOY: created .env from template" | |
| fi | |
| # Inject secrets | |
| sed -i "s|^CMS_DB_PASSWORD=.*|CMS_DB_PASSWORD=${DB_PASSWORD}|" .env | |
| sed -i "s|^SECRET_KEY=.*|SECRET_KEY=${DJANGO_SECRET_KEY}|" .env | |
| sed -i "s|^FLOODPROOFS_SFTP_HOST=.*|FLOODPROOFS_SFTP_HOST=${FLOODPROOFS_SFTP_HOST}|" .env | |
| sed -i "s|^FLOODPROOFS_SFTP_USER=.*|FLOODPROOFS_SFTP_USER=${FLOODPROOFS_SFTP_USER}|" .env | |
| sed -i "s|^FLOODPROOFS_SFTP_PASSWORD=.*|FLOODPROOFS_SFTP_PASSWORD=${FLOODPROOFS_SFTP_PASSWORD}|" .env | |
| sed -i "s|^WRF_FTP_HOST=.*|WRF_FTP_HOST=${WRF_FTP_HOST}|" .env | |
| sed -i "s|^WRF_FTP_USER=.*|WRF_FTP_USER=${WRF_FTP_USER}|" .env | |
| sed -i "s|^WRF_FTP_PASSWORD=.*|WRF_FTP_PASSWORD=${WRF_FTP_PASSWORD}|" .env | |
| sed -i "s|^FLOODS_API_KEY=.*|FLOODS_API_KEY=${FLOODS_API_KEY}|" .env | |
| sed -i "s|^SMTP_EMAIL_HOST=.*|SMTP_EMAIL_HOST=${SMTP_EMAIL_HOST}|" .env | |
| sed -i "s|^SMTP_EMAIL_HOST_USER=.*|SMTP_EMAIL_HOST_USER=${SMTP_EMAIL_HOST_USER}|" .env | |
| sed -i "s|^SMTP_EMAIL_HOST_PASSWORD=.*|SMTP_EMAIL_HOST_PASSWORD=${SMTP_EMAIL_HOST_PASSWORD}|" .env | |
| sed -i "s|^CMS_DEBUG=.*|CMS_DEBUG=False|" .env | |
| # If no services to deploy, just update repo and exit | |
| if [ -z "${DEPLOY_SERVICES}" ]; then | |
| echo "No services to deploy — repo updated, exiting" | |
| exit 0 | |
| fi | |
| # Deploy: pull by SHA, retag as latest, restart | |
| chmod +x scripts/deploy.sh | |
| ./scripts/deploy.sh ${DEPLOY_SERVICES} |