Skip to content

feat: Add video browsing support and harden image-only analysis flows #269

feat: Add video browsing support and harden image-only analysis flows

feat: Add video browsing support and harden image-only analysis flows #269

Workflow file for this run

name: CI
on:
push:
branches: [ main ]
pull_request: {}
schedule:
- cron: '0 3 * * 1' # Weekly (Mon 03:00 UTC) security & maintenance run
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
build-test:
name: Lint & Test (Python)
runs-on: ubuntu-latest
timeout-minutes: 25
permissions:
contents: read
pull-requests: write
env:
PIP_DISABLE_PIP_VERSION_CHECK: '1'
PIP_NO_PYTHON_VERSION_WARNING: '1'
PIP_PROGRESS_BAR: 'off'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install system deps
run: |
sudo apt-get update
# Base GL/GLib plus EGL for headless PyQt6 usage
sudo apt-get install -y libgl1 libglib2.0-0 libegl1
# QtMultimedia runtime deps used by PyQt6 on Linux runners
sudo apt-get install -y libpulse0 libpulse-mainloop-glib0
# JPEG tools for lossless JPEG rotation
sudo apt-get install -y libjpeg-turbo-progs
- name: Cache pip
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt', '**/requirements-dev.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies (prod + dev)
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
pip install openai
- name: Ruff Lint
run: ruff check .
- name: Ruff Format Check
run: ruff format --check .
- name: Run Tests
env:
PYTHONWARNINGS: default
# Ensure Qt runs without an X server
QT_QPA_PLATFORM: offscreen
run: |
pytest -q --cov=src --cov-report=xml:coverage.xml --cov-report=term
# Single coverage dataset only; no secondary copying.
- name: Smoke launch (headless)
env:
QT_QPA_PLATFORM: offscreen
PHOTOSORT_ENABLE_FILE_LOGGING: 'false'
run: |
# Launch the app briefly in headless mode to catch startup regressions
timeout 20s python src/main.py --smoke-test --smoke-delay-ms 1500
- name: Upload coverage XML
uses: actions/upload-artifact@v4
if: success() || failure()
with:
name: coverage-xml
path: coverage.xml
retention-days: 5
- name: Upload pytest cache & reports
uses: actions/upload-artifact@v4
if: success() || failure()
with:
name: pytest-artifacts
path: |
.pytest_cache/
./**/pytest-*.log
if-no-files-found: ignore
retention-days: 5
security:
name: Basic Security Scan
runs-on: ubuntu-latest
needs: [build-test]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Cache pip
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install deps (no extras)
run: |
python -m pip install --upgrade pip
pip install pip-audit
pip install -r requirements.txt || true
- name: pip-audit (non-failing)
continue-on-error: true
run: |
pip-audit -r requirements.txt -f json -o pip-audit.json || true
- name: Upload pip-audit report
uses: actions/upload-artifact@v4
with:
name: pip-audit-report
path: pip-audit.json
retention-days: 5
summary:
name: PR Summary
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
needs: [build-test, security]
permissions:
contents: read
pull-requests: write
steps:
- name: Download coverage artifacts
uses: actions/download-artifact@v4
with:
path: coverage-artifacts
- name: Summarize Coverage
run: |
echo '### Coverage Summary' >> $GITHUB_STEP_SUMMARY
if [ -f coverage-artifacts/coverage-xml/coverage.xml ]; then
TOTAL=$(grep -o 'line-rate="[0-9.]*"' coverage-artifacts/coverage-xml/coverage.xml | head -1 | cut -d '"' -f2)
echo "* Line-rate: ${TOTAL}" >> $GITHUB_STEP_SUMMARY
else
echo '* Coverage XML not found' >> $GITHUB_STEP_SUMMARY
fi
- name: Generate Summary
run: |
echo '### CI Results' >> $GITHUB_STEP_SUMMARY
echo '* Build/Test: ${{ needs.build-test.result }}' >> $GITHUB_STEP_SUMMARY
echo '* Security: ${{ needs.security.result }}' >> $GITHUB_STEP_SUMMARY