name: CI/CD Pipeline on: push: branches: [ main ] pull_request: branches: [ main ] jobs: unit-tests: name: Unit Tests runs-on: ubuntu-latest strategy: matrix: python-version: ['3.10', '3.11', '3.12'] steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: 'pip' - name: Install uv uses: astral-sh/setup-uv@v4 with: version: "0.5.11" - name: Install dependencies run: | uv sync --all-extras --dev - name: Run unit tests run: | uv run pytest test_bot.py -m "not integration" --cov=bot --cov=main --cov-report=xml --cov-report=term - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 with: file: ./coverage.xml flags: unittests name: codecov-${{ matrix.python-version }} fail_ci_if_error: false integration-tests: name: Integration Tests runs-on: ubuntu-latest strategy: matrix: python-version: ['3.10', '3.11', '3.12'] steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: 'pip' - name: Install uv uses: astral-sh/setup-uv@v4 with: version: "0.5.11" - name: Install dependencies run: | uv sync --all-extras --dev - name: Run integration tests run: | uv run pytest test_integration.py --cov=bot --cov-report=xml --cov-report=term --cov-fail-under=70 - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 with: file: ./coverage.xml flags: integration name: codecov-integration-${{ matrix.python-version }} fail_ci_if_error: false code-quality: name: Code Quality runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.11' cache: 'pip' - name: Install uv uses: astral-sh/setup-uv@v4 with: version: "0.5.11" - name: Install dependencies run: | uv sync --all-extras --dev - name: Run ruff check run: | uv run ruff check . - name: Run ruff format run: | uv run ruff format --check . - name: Run mypy run: | uv run mypy bot.py main.py --ignore-missing-imports continue-on-error: true docker-build-test: name: Docker Build Test runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build Docker image uses: docker/build-push-action@v5 with: context: . load: true tags: masto-rss:test cache-from: type=gha cache-to: type=gha,mode=max - name: Test Docker image structure run: | docker run --rm masto-rss:test python --version docker run --rm masto-rss:test python -c "import feedparser; print(feedparser.__version__)" docker run --rm masto-rss:test python -c "import mastodon; print(mastodon.__version__)" all-tests-pass: name: All Tests Passed needs: [unit-tests, integration-tests, code-quality, docker-build-test] runs-on: ubuntu-latest if: always() steps: - name: Check test results run: | if [ "${{ needs.unit-tests.result }}" != "success" ]; then echo "Unit tests failed" exit 1 fi if [ "${{ needs.integration-tests.result }}" != "success" ]; then echo "Integration tests failed" exit 1 fi if [ "${{ needs.code-quality.result }}" != "success" ]; then echo "Code quality checks failed" exit 1 fi if [ "${{ needs.docker-build-test.result }}" != "success" ]; then echo "Docker build test failed" exit 1 fi echo "All tests passed successfully!" deploy-image: name: Build & Push Image needs: [all-tests-pass] # Only run on push to main, not on PRs (though PRs are implicitly filtered by `push` check in `if` usually, explicit is better) # Actually, we want to run this job only if it IS a push event. if: github.event_name == 'push' && github.ref == 'refs/heads/main' runs-on: ubuntu-latest permissions: contents: read packages: write steps: - uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub uses: docker/login-action@v3 with: username: amitserper password: ${{ secrets.DH_PASSWORD }} - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: | amitserper/masto-rss ghcr.io/aserper/masto-rss tags: | type=ref,event=branch type=sha,prefix={{branch}}- type=raw,value=latest,enable={{is_default_branch}} - name: Build and push multiarch image uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max