Merge pull request #639 from PROCOLLAB-github/devops-structure-rework #413
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
| name: Deploy Dev | |
| on: | |
| push: | |
| branches: | |
| - dev | |
| workflow_dispatch: | |
| jobs: | |
| deploy: | |
| name: Deploy | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Deploy to server | |
| uses: garygrossgarten/github-action-ssh@release | |
| with: | |
| host: ${{ secrets.DEV_SERVER_HOST }} | |
| username: ${{ secrets.DEV_SERVER_USER }} | |
| password: ${{ secrets.DEV_SERVER_PASSWORD }} | |
| command: | | |
| set -eu | |
| cd /root/api | |
| git fetch --all --tags --prune | |
| git branch -r --contains "${{ github.sha }}" | grep -q 'origin/dev' | |
| git checkout --detach "${{ github.sha }}" | |
| git rev-parse HEAD | |
| export IMAGE_TAG="${{ github.sha }}" | |
| rm -f .env | |
| touch .env | |
| echo "DJANGO_SECRET_KEY=${{ secrets.DEV_DJANGO_SECRET_KEY }}" >> .env | |
| echo "DATABASE_NAME=${{ secrets.DEV_DATABASE_NAME }}" >> .env | |
| echo "DATABASE_PASSWORD=${{ secrets.DEV_DATABASE_PASSWORD }}" >> .env | |
| echo "DATABASE_USER=${{ secrets.DEV_DATABASE_USER }}" >> .env | |
| echo "DATABASE_HOST=${{ secrets.DEV_DATABASE_HOST }}" >> .env | |
| echo "DATABASE_PORT=${{ secrets.DEV_DATABASE_PORT }}" >> .env | |
| echo "SELECTEL_ACCOUNT_ID=${{ secrets.SELECTEL_ACCOUNT_ID }}" >> .env | |
| echo "SELECTEL_CONTAINER_NAME=${{ secrets.SELECTEL_CONTAINER_NAME }}" >> .env | |
| echo "SELECTEL_CONTAINER_PASSWORD=${{ secrets.SELECTEL_CONTAINER_PASSWORD }}" >> .env | |
| echo "SELECTEL_CONTAINER_USERNAME=${{ secrets.SELECTEL_CONTAINER_USERNAME }}" >> .env | |
| echo "EMAIL_USER=${{ secrets.EMAIL_USER }}" >> .env | |
| echo "UNISENDER_GO_API_KEY=${{ secrets.UNISENDER_GO_API_KEY }}" >> .env | |
| chmod 600 .env | |
| docker compose -f docker-compose.dev-ci.yml config >/dev/null | |
| docker compose -f docker-compose.dev-ci.yml build web && | |
| docker compose -f docker-compose.dev-ci.yml run --rm web python manage.py migrate && | |
| docker compose -f docker-compose.dev-ci.yml up -d --force-recreate && | |
| expected_image="procollab-dev-api:${IMAGE_TAG}" && | |
| for service in web celerys; do | |
| container="$(docker compose -f docker-compose.dev-ci.yml ps -q "$service")" | |
| if [ -z "$container" ]; then | |
| echo "Service ${service} has no running container" >&2 | |
| docker compose -f docker-compose.dev-ci.yml ps >&2 || true | |
| exit 1 | |
| fi | |
| actual_image="$(docker inspect -f '{{.Config.Image}}' "$container")" | |
| echo "Service ${service}: container=${container} image=${actual_image}" | |
| if [ "$actual_image" != "$expected_image" ]; then | |
| echo "Service ${service} uses unexpected image: ${actual_image}, expected ${expected_image}" >&2 | |
| docker compose -f docker-compose.dev-ci.yml ps >&2 || true | |
| exit 1 | |
| fi | |
| done && | |
| install -d /etc/nginx/procollab/includes && | |
| install -m 644 deploy/nginx/host/includes/proxy_app.inc /etc/nginx/procollab/includes/proxy_app.inc && | |
| install -m 644 deploy/nginx/host/dev/dev.procollab.ru /etc/nginx/sites-available/dev.procollab.ru && | |
| ln -sfn /etc/nginx/sites-available/dev.procollab.ru /etc/nginx/sites-enabled/dev.procollab.ru && | |
| if [ "$(id -u)" -eq 0 ]; then | |
| nginx -t && | |
| systemctl reload nginx | |
| else | |
| sudo nginx -t && | |
| sudo systemctl reload nginx | |
| fi && | |
| for attempt in $(seq 1 24); do | |
| root_status="$(curl -s -o /dev/null -w '%{http_code}' https://dev.procollab.ru/ || true)" && | |
| admin_status="$(curl -s -o /dev/null -w '%{http_code}' https://dev.procollab.ru/admin/login/ || true)" && | |
| if [ "$root_status" = "401" ] && [ "$admin_status" = "200" ]; then | |
| echo "Smoke check passed on attempt ${attempt}" && | |
| break | |
| fi | |
| sleep 5 | |
| done && | |
| if [ "$root_status" != "401" ] || [ "$admin_status" != "200" ]; then | |
| echo "Smoke check failed: /=${root_status} /admin/login/=${admin_status}" >&2 && | |
| exit 1 | |
| fi && | |
| docker compose -f docker-compose.dev-ci.yml ps | |
| celery_status="" | |
| celery_ping="" | |
| celery_container="" | |
| for attempt in $(seq 1 12); do | |
| celery_container="$(docker compose -f docker-compose.dev-ci.yml ps -q celerys 2>/dev/null || true)" | |
| if [ -n "$celery_container" ]; then | |
| celery_status="$(docker inspect -f '{{.State.Status}}' "$celery_container" 2>/dev/null || true)" | |
| else | |
| celery_status="missing" | |
| fi | |
| echo "Celery check attempt ${attempt}: container=${celery_container:-missing} status=${celery_status}" | |
| if [ "$celery_status" = "running" ]; then | |
| celery_ping="$(docker compose -f docker-compose.dev-ci.yml exec -T celerys sh -lc 'celery -A procollab inspect ping --timeout=15' 2>&1 || true)" | |
| printf '%s\n' "$celery_ping" | |
| if printf '%s\n' "$celery_ping" | grep -q 'pong'; then | |
| echo "Celery check passed on attempt ${attempt}" | |
| break | |
| fi | |
| fi | |
| sleep 5 | |
| done | |
| if [ "$celery_status" != "running" ] || ! printf '%s\n' "$celery_ping" | grep -q 'pong'; then | |
| echo "Celery check failed: status=${celery_status}" >&2 | |
| docker compose -f docker-compose.dev-ci.yml ps >&2 || true | |
| docker compose -f docker-compose.dev-ci.yml logs --tail=200 celerys >&2 || true | |
| docker compose -f docker-compose.dev-ci.yml logs --tail=100 redis >&2 || true | |
| docker compose -f docker-compose.dev-ci.yml logs --tail=100 web >&2 || true | |
| exit 1 | |
| fi |