docs: testing locally small comment #17
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: CI/CD Pipeline | |
| on: | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| branches: [ main ] | |
| env: | |
| DOCKER_IMAGE: ${{ secrets.DOCKERHUB_USERNAME }}/taskmanager | |
| jobs: | |
| # JOB 1: Test | |
| test: | |
| name: Run Tests & Linting | |
| runs-on: ubuntu-latest | |
| services: | |
| postgres: | |
| image: postgres:15-alpine | |
| env: | |
| POSTGRES_DB: taskmanager_test | |
| POSTGRES_USER: postgres | |
| POSTGRES_PASSWORD: postgres | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| env: | |
| # DJANGO_SETTINGS_MODULE: taskmanager.settings.development | |
| SECRET_KEY: test-secret-key-for-ci-only | |
| DATABASE_URL: postgresql://postgres:postgres@localhost:5432/taskmanager_test | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python 3.11 | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Cache pip dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/pip | |
| key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pip- | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -r requirements.txt | |
| pip install flake8 pytest pytest-django coverage | |
| - name: Run flake8 linting | |
| run: | | |
| flake8 . --max-line-length=120 \ | |
| --exclude=venv,migrations,staticfiles,__pycache__ \ | |
| --count --statistics | |
| - name: Run pytest | |
| run: | | |
| pytest --tb=short -v | |
| - name: Run coverage report | |
| run: | | |
| coverage run -m pytest | |
| coverage report --fail-under=60 | |
| # JOB 2: Build and Push Docker Image | |
| build: | |
| name: Build & Push Docker Image | |
| runs-on: ubuntu-latest | |
| needs: test | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' | |
| outputs: | |
| image_tag: ${{ steps.meta.outputs.version }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Extract metadata for Docker | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.DOCKER_IMAGE }} | |
| tags: | | |
| type=raw,value=latest | |
| type=sha,prefix=sha-,format=short | |
| - name: Build and push Docker image | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| target: production | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| # JOB 3: Deploy to Server | |
| deploy: | |
| name: Deploy to Production | |
| runs-on: ubuntu-latest | |
| needs: build | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Deploy via SSH | |
| uses: appleboy/ssh-action@v1.0.3 | |
| with: | |
| host: ${{ secrets.SSH_HOST }} | |
| username: ${{ secrets.SSH_USERNAME }} | |
| key: ${{ secrets.SSH_PRIVATE_KEY }} | |
| script: | | |
| cd ~/taskmanager | |
| echo "Pulling latest Docker image..." | |
| docker compose pull | |
| echo "Stopping old containers..." | |
| docker compose down --remove-orphans | |
| echo "Starting new containers..." | |
| docker compose up -d | |
| echo "Waiting for web container to be ready..." | |
| sleep 5 | |
| echo "Running migrations..." | |
| docker compose exec -T web python manage.py migrate --noinput | |
| echo "Collecting static files..." | |
| docker compose exec -T web python manage.py collectstatic --noinput | |
| echo "Cleaning up old Docker images..." | |
| docker image prune -f | |
| echo "Deployment complete! App running at http://${{ secrets.SSH_HOST }}" | |