With Actions enabled
git --version
Create a full CI/CD workflow: lint, test, build, scan, and deploy on push to main.
1 name: CI/CD Pipeline 2 3 on: 4 push: 5 branches: [main, "release/**"] 6 pull_request: 7 branches: [main] 8 9 concurrency: 10 group: ${{ github.workflow }}-${{ github.ref }} 11 cancel-in-progress: ${{ github.event_name == 'pull_request' }} 12 13 jobs: 14 lint-and-test: 15 name: Lint & Test 16 runs-on: ubuntu-latest 17 timeout-minutes: 15 18 19 strategy: 20 matrix: 21 python-version: ["3.11", "3.12"] 22 23 steps: 24 - uses: actions/checkout@v4 25 26 - name: Set up Python ${{ matrix.python-version }} 27 uses: actions/setup-python@v5 28 with: 29 python-version: ${{ matrix.python-version }} 30 31 - name: Cache pip packages 32 uses: actions/cache@v4 33 with: 34 path: ~/.cache/pip 35 key: pip-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('requirements*.txt') }} 36 restore-keys: pip-${{ runner.os }}-${{ matrix.python-version }}- 37 38 - name: Install dependencies 39 run: pip install -r requirements.txt -r requirements-dev.txt 40 41 - name: Lint (ruff) 42 run: ruff check . --output-format=github 43 44 - name: Type check (mypy) 45 run: mypy src/ 46 47 - name: Run tests with coverage 48 run: | 49 pytest tests/ --cov=src --cov-report=xml --cov-fail-under=80 -v 50 51 - name: Upload coverage 52 uses: codecov/codecov-action@v4 53 if: matrix.python-version == '3.11' 54 with: 55 token: ${{ secrets.CODECOV_TOKEN }} 56 files: coverage.xml 57 58 build-image: 59 name: Build Image 60 needs: lint-and-test 61 runs-on: ubuntu-latest 62 timeout-minutes: 20 63 outputs: 64 image-tag: ${{ steps.meta.outputs.version }} 65 66 steps: 67 - uses: actions/checkout@v4 68 69 - name: Set up Docker Buildx 70 uses: docker/setup-buildx-action@v3 71 72 - name: Extract metadata 73 id: meta 74 uses: docker/metadata-action@v5 75 with: 76 images: ghcr.io/${{ github.repository }} 77 tags: | 78 type=sha,prefix=,format=short 79 type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} 80 81 - name: Build image 82 uses: docker/build-push-action@v5 83 with: 84 context: . 85 push: false 86 load: true 87 tags: ${{ steps.meta.outputs.tags }} 88 cache-from: type=gha 89 cache-to: type=gha,mode=max 90 91 deploy-staging: 92 name: Deploy to Staging 93 needs: build-image 94 runs-on: ubuntu-latest 95 if: github.ref == 'refs/heads/main' 96 environment: 97 name: staging 98 url: https://staging.myapp.com 99 100 steps: 101 - uses: actions/checkout@v4 102 - name: Deploy to staging 103 run: | 104 echo "Deploying tag ${{ needs.build-image.outputs.image-tag }}" 105 # kubectl set image deployment/api api=ghcr.io/org/repo:$TAG 106 107 deploy-production: 108 name: Deploy to Production 109 needs: deploy-staging 110 runs-on: ubuntu-latest 111 if: github.ref == 'refs/heads/main' 112 environment: 113 name: production 114 url: https://myapp.com 115 116 steps: 117 - uses: actions/checkout@v4 118 - name: Deploy to production 119 env: 120 PROD_API_KEY: ${{ secrets.PROD_API_KEY }} 121 run: echo "Production deploy with approval gate" 122
Sign in to share your feedback and join the discussion.