ci: gate docker push via env vars #9
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: [master, main, develop] | |
| pull_request: | |
| branches: [master, main, develop] | |
| release: | |
| types: [published] | |
| workflow_dispatch: | |
| jobs: | |
| test: | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, windows-latest, macos-latest] | |
| python-version: ["3.12"] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Set up uv | |
| uses: astral-sh/setup-uv@v5 | |
| with: | |
| enable-cache: true | |
| - name: Install system dependencies (Ubuntu) | |
| if: matrix.os == 'ubuntu-latest' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y ffmpeg libsm6 libxext6 libxrender1 libglib2.0-0 | |
| sudo apt-get install -y cmake build-essential | |
| - name: Install system dependencies (macOS) | |
| if: matrix.os == 'macos-latest' | |
| run: | | |
| brew install ffmpeg cmake | |
| - name: Install system dependencies (Windows) | |
| if: matrix.os == 'windows-latest' | |
| run: | | |
| choco install ffmpeg cmake | |
| - name: Install dependencies | |
| run: | | |
| uv sync --dev | |
| - name: Lint (ruff - minimal) | |
| run: | | |
| uv run ruff check src/videoannotator tests --select=E9,F63,F7,F82 | |
| - name: Type check with mypy | |
| if: github.event_name == 'workflow_dispatch' | |
| run: | | |
| uv run mypy src/videoannotator | |
| - name: Test with pytest | |
| run: | | |
| uv run pytest -q --cov=src/videoannotator --cov-report=xml --cov-report=term-missing | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@v3 | |
| with: | |
| file: ./coverage.xml | |
| flags: unittests | |
| name: codecov-umbrella | |
| fail_ci_if_error: false | |
| integration-test: | |
| runs-on: ubuntu-latest | |
| needs: test | |
| if: github.event_name == 'workflow_dispatch' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python 3.12 | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: "3.12" | |
| - name: Set up uv | |
| uses: astral-sh/setup-uv@v5 | |
| with: | |
| enable-cache: true | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y cmake build-essential | |
| sudo apt-get install -y ffmpeg libsm6 libxext6 libxrender1 libglib2.0-0 | |
| - name: Install dependencies | |
| run: | | |
| uv sync --dev | |
| - name: Run integration tests | |
| run: | | |
| uv run pytest -q -m integration | |
| - name: Test CLI interface | |
| run: | | |
| uv run videoannotator --help | |
| uv run videoannotator server --help | |
| performance-test: | |
| runs-on: ubuntu-latest | |
| needs: test | |
| if: github.event_name == 'workflow_dispatch' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python 3.12 | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: "3.12" | |
| - name: Set up uv | |
| uses: astral-sh/setup-uv@v5 | |
| with: | |
| enable-cache: true | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y ffmpeg libsm6 libxext6 libxrender1 libglib2.0-0 | |
| sudo apt-get install -y cmake build-essential | |
| - name: Install dependencies | |
| run: | | |
| uv sync --dev | |
| - name: Run performance tests | |
| run: | | |
| uv run pytest -q -m performance --benchmark-only --benchmark-json=benchmark.json | |
| - name: Store benchmark result | |
| uses: benchmark-action/github-action-benchmark@v1 | |
| with: | |
| name: Python Benchmark | |
| tool: "pytest" | |
| output-file-path: benchmark.json | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| auto-push: true | |
| security-scan: | |
| runs-on: ubuntu-latest | |
| needs: test | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Run Trivy vulnerability scanner | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| scan-type: "fs" | |
| scan-ref: "." | |
| format: "sarif" | |
| output: "trivy-results.sarif" | |
| - name: Upload Trivy scan results to GitHub Security tab | |
| uses: github/codeql-action/upload-sarif@v2 | |
| with: | |
| sarif_file: "trivy-results.sarif" | |
| build-and-publish: | |
| runs-on: ubuntu-latest | |
| needs: [test, integration-test] | |
| if: github.event_name == 'release' && github.event.action == 'published' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python 3.12 | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: "3.12" | |
| - name: Install build dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install build twine | |
| - name: Build package | |
| run: | | |
| python -m build | |
| - name: Check package | |
| run: | | |
| twine check dist/* | |
| - name: Publish to PyPI | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| user: __token__ | |
| password: ${{ secrets.PYPI_API_TOKEN }} | |
| docker-build: | |
| runs-on: ubuntu-latest | |
| needs: [test, integration-test] | |
| if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop') | |
| env: | |
| DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} | |
| DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v2 | |
| - name: Check Docker Hub secrets | |
| run: | | |
| if [ -z "${{ secrets.DOCKER_USERNAME }}" ] || [ -z "${{ secrets.DOCKER_PASSWORD }}" ]; then | |
| echo "Docker Hub credentials not configured; skipping docker push steps." | |
| else | |
| echo "Docker Hub credentials present." | |
| fi | |
| - name: Login to Docker Hub | |
| if: ${{ env.DOCKER_USERNAME != '' && env.DOCKER_PASSWORD != '' }} | |
| uses: docker/login-action@v2 | |
| with: | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_PASSWORD }} | |
| - name: Extract metadata | |
| id: meta | |
| uses: docker/metadata-action@v4 | |
| with: | |
| images: videoannotator/videoannotator | |
| tags: | | |
| type=ref,event=branch | |
| type=ref,event=pr | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| - name: Build and push Docker image | |
| if: ${{ env.DOCKER_USERNAME != '' && env.DOCKER_PASSWORD != '' }} | |
| uses: docker/build-push-action@v4 | |
| with: | |
| context: . | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max |