name: CI on: pull_request: push: branches: - main schedule: - cron: "0 2 * * *" concurrency: group: ci-pr-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: ci: if: github.event_name == 'pull_request' runs-on: ubuntu-latest env: CI_IMAGE: nohype-ci:${{ github.run_id }} steps: - uses: actions/checkout@v4 - name: Build run: docker build -t "$CI_IMAGE" . - name: Start PostgreSQL run: | docker run -d --name ci-postgres \ -e POSTGRES_DB=nohype \ -e POSTGRES_USER=nohype \ -e POSTGRES_PASSWORD=nohype \ postgres:16-alpine for i in $(seq 1 30); do if docker exec ci-postgres pg_isready -U nohype -d nohype >/dev/null; then exit 0 fi sleep 2 done docker logs ci-postgres || true exit 1 - name: Ruff run: docker run --rm --network container:ci-postgres -e SECRET_KEY=ci-secret-key -e DATABASE_URL=postgres://nohype:nohype@127.0.0.1:5432/nohype "$CI_IMAGE" ruff check . - name: Mypy run: docker run --rm --network container:ci-postgres -e SECRET_KEY=ci-secret-key -e DATABASE_URL=postgres://nohype:nohype@127.0.0.1:5432/nohype "$CI_IMAGE" mypy apps config - name: Pytest run: docker run --rm --network container:ci-postgres -e SECRET_KEY=ci-secret-key -e DATABASE_URL=postgres://nohype:nohype@127.0.0.1:5432/nohype "$CI_IMAGE" pytest --ignore=e2e - name: Tailwind build (assert generated diff is clean) run: | docker run --name ci-tailwind \ --network container:ci-postgres \ -e SECRET_KEY=ci-secret-key \ -e DATABASE_URL=postgres://nohype:nohype@127.0.0.1:5432/nohype \ "$CI_IMAGE" \ sh -lc "python manage.py tailwind install --no-input && python manage.py tailwind build" docker cp ci-tailwind:/app/theme/static/css/styles.css /tmp/ci-styles.css docker rm -f ci-tailwind cmp -s theme/static/css/styles.css /tmp/ci-styles.css - name: Remove PostgreSQL if: always() run: | docker rm -f ci-postgres || true - name: Remove CI image if: always() run: docker image rm -f "$CI_IMAGE" || true pr-e2e: if: github.event_name == 'pull_request' runs-on: ubuntu-latest env: CI_IMAGE: nohype-ci-e2e:${{ github.run_id }} PLAYWRIGHT_CACHE_VOLUME: nohype-playwright-browsers steps: - uses: actions/checkout@v4 - name: Build run: docker build -t "$CI_IMAGE" . - name: Ensure Playwright Chromium cache run: | docker volume create "$PLAYWRIGHT_CACHE_VOLUME" >/dev/null docker run --rm \ -v "$PLAYWRIGHT_CACHE_VOLUME:/ms-playwright" \ -e PLAYWRIGHT_BROWSERS_PATH=/ms-playwright \ "$CI_IMAGE" \ python -m playwright install chromium - name: Start PostgreSQL run: | docker run -d --name pr-e2e-postgres \ -e POSTGRES_DB=nohype \ -e POSTGRES_USER=nohype \ -e POSTGRES_PASSWORD=nohype \ postgres:16-alpine for i in $(seq 1 30); do if docker exec pr-e2e-postgres pg_isready -U nohype -d nohype >/dev/null; then exit 0 fi sleep 2 done docker logs pr-e2e-postgres || true exit 1 - name: Start app with seeded content run: | docker run -d --name pr-e2e-app --network container:pr-e2e-postgres \ -v "$PLAYWRIGHT_CACHE_VOLUME:/ms-playwright:ro" \ -e SECRET_KEY=ci-secret-key \ -e DATABASE_URL=postgres://nohype:nohype@127.0.0.1:5432/nohype \ -e CONSENT_POLICY_VERSION=1 \ -e EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend \ -e DEFAULT_FROM_EMAIL=hello@nohypeai.com \ -e NEWSLETTER_PROVIDER=buttondown \ -e PLAYWRIGHT_BROWSERS_PATH=/ms-playwright \ "$CI_IMAGE" \ sh -lc "python manage.py migrate --noinput && python manage.py seed_e2e_content && python manage.py runserver 0.0.0.0:8000" for i in $(seq 1 40); do if docker exec pr-e2e-app curl -fsS http://127.0.0.1:8000/ >/dev/null; then exit 0 fi sleep 2 done docker logs pr-e2e-app || true exit 1 - name: Run E2E tests run: | docker exec -e E2E_BASE_URL=http://127.0.0.1:8000 pr-e2e-app \ pytest e2e/ -o addopts='' -q --tb=short - name: Remove containers if: always() run: | docker rm -f pr-e2e-app || true docker rm -f pr-e2e-postgres || true - name: Remove CI image if: always() run: docker image rm -f "$CI_IMAGE" || true nightly-e2e: if: github.event_name == 'schedule' runs-on: ubuntu-latest env: CI_IMAGE: nohype-ci-nightly:${{ github.run_id }} PLAYWRIGHT_CACHE_VOLUME: nohype-playwright-browsers steps: - uses: actions/checkout@v4 - name: Build run: docker build -t "$CI_IMAGE" . - name: Ensure Playwright Chromium cache run: | docker volume create "$PLAYWRIGHT_CACHE_VOLUME" >/dev/null docker run --rm \ -v "$PLAYWRIGHT_CACHE_VOLUME:/ms-playwright" \ -e PLAYWRIGHT_BROWSERS_PATH=/ms-playwright \ "$CI_IMAGE" \ python -m playwright install chromium - name: Start PostgreSQL run: | docker run -d --name nightly-postgres \ -e POSTGRES_DB=nohype \ -e POSTGRES_USER=nohype \ -e POSTGRES_PASSWORD=nohype \ postgres:16-alpine for i in $(seq 1 30); do if docker exec nightly-postgres pg_isready -U nohype -d nohype >/dev/null; then exit 0 fi sleep 2 done docker logs nightly-postgres || true exit 1 - name: Start dev server with seeded content run: | docker run -d --name nightly-e2e --network container:nightly-postgres \ -v "$PLAYWRIGHT_CACHE_VOLUME:/ms-playwright:ro" \ -e SECRET_KEY=ci-secret-key \ -e DATABASE_URL=postgres://nohype:nohype@127.0.0.1:5432/nohype \ -e CONSENT_POLICY_VERSION=1 \ -e EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend \ -e DEFAULT_FROM_EMAIL=hello@nohypeai.com \ -e NEWSLETTER_PROVIDER=buttondown \ -e PLAYWRIGHT_BROWSERS_PATH=/ms-playwright \ "$CI_IMAGE" \ sh -lc "python manage.py migrate --noinput && python manage.py seed_e2e_content && python manage.py runserver 0.0.0.0:8000" for i in $(seq 1 40); do if docker exec nightly-e2e curl -fsS http://127.0.0.1:8000/ >/dev/null; then exit 0 fi sleep 2 done docker logs nightly-e2e || true exit 1 - name: Run Playwright E2E tests run: | docker exec -e E2E_BASE_URL=http://127.0.0.1:8000 nightly-e2e \ pytest e2e/ apps/core/tests/test_nightly_e2e_playwright.py -o addopts='' -q --tb=short - name: Remove nightly container if: always() run: | docker rm -f nightly-e2e || true docker rm -f nightly-postgres || true - name: Remove CI image if: always() run: docker image rm -f "$CI_IMAGE" || true deploy: if: github.event_name == 'push' && github.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: - name: Deploy to lintel-prod-01 uses: appleboy/ssh-action@v1 with: host: ${{ secrets.PROD_SSH_HOST }} username: deploy key: ${{ secrets.PROD_SSH_KEY }} script: bash /srv/sum/nohype/app/deploy/deploy.sh