name: CI on: push: branches: [main] paths-ignore: - "**/*.md" - "docs/**" - ".env.example" - "LICENSE" - "FUNDING.yml" pull_request: branches: [main] permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: lint: name: Lint runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v7 - name: Set up Python uses: actions/setup-python@v7 with: python-version-file: ".python-version" cache: pip - name: Set up Node uses: actions/setup-node@v7 with: node-version: 24 cache: npm - name: Install frontend deps run: npm ci - name: Run pre-commit uses: pre-commit/action@v3.0.1 frontend: name: Frontend runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v7 - name: Set up Node uses: actions/setup-node@v7 with: node-version: 24 cache: npm - name: Install dependencies run: npm ci - name: Typecheck run: npx tsc --noEmit - name: Unit tests run: npm run test:frontend - name: Upload test results uses: actions/upload-artifact@v7 if: always() with: name: vitest-results path: vitest-junit.xml retention-days: 14 - name: Build run: npm run build test: name: Test runs-on: ubuntu-latest timeout-minutes: 30 services: postgres: # Pinned to match the bundled postgres:17-alpine in docker-compose.yml image: postgres:17 env: POSTGRES_USER: meshcorehub POSTGRES_PASSWORD: meshcorehub-test POSTGRES_DB: meshcorehub_test ports: - 5432:5432 options: >- --health-cmd "pg_isready -U meshcorehub -d meshcorehub_test" --health-interval 5s --health-timeout 5s --health-retries 10 redis: # Pinned to match the bundled redis:8-alpine in docker-compose.yml image: redis:8 ports: - 6379:6379 options: >- --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 10 steps: - uses: actions/checkout@v7 - name: Set up Python uses: actions/setup-python@v7 with: python-version-file: ".python-version" cache: pip - name: Install dependencies run: | python -m pip install --upgrade pip pip install -e ".[dev]" - name: Run tests with pytest env: TEST_POSTGRES_URL: postgresql+psycopg2://meshcorehub:meshcorehub-test@localhost:5432/meshcorehub_test TEST_REDIS_URL: redis://localhost:6379/0 run: | pytest -nauto --cov=meshcore_hub --cov-report=xml --cov-report=term-missing --junitxml=junit.xml -o junit_family=legacy - name: Upload test results uses: actions/upload-artifact@v7 if: always() with: name: pytest-results path: | junit.xml coverage.xml retention-days: 14 - name: Upload coverage to Codecov uses: codecov/codecov-action@v7 if: always() with: files: ./coverage.xml fail_ci_if_error: false verbose: true token: ${{ secrets.CODECOV_TOKEN }} - name: Upload test results to Codecov uses: codecov/codecov-action@v7 if: ${{ !cancelled() }} with: report_type: test_results token: ${{ secrets.CODECOV_TOKEN }} e2e: name: E2E (Playwright) runs-on: ubuntu-latest timeout-minutes: 45 steps: - uses: actions/checkout@v7 - name: Set up Python uses: actions/setup-python@v7 with: python-version-file: ".python-version" - name: Set up Node uses: actions/setup-node@v7 with: node-version: 24 cache: npm - name: Install frontend deps run: npm ci - name: Install Playwright browsers run: npx playwright install --with-deps chromium - name: Set up Python env for mint_session.py run: | python -m venv .venv .venv/bin/pip install itsdangerous - name: Build e2e stack run: docker compose -f e2e/docker-compose.test.yml build - name: Start e2e stack run: docker compose -f e2e/docker-compose.test.yml up -d --wait - name: Run E2E tests run: npm run test:e2e - name: Upload Playwright report uses: actions/upload-artifact@v7 if: always() with: name: playwright-report path: | e2e/playwright-report/ e2e/test-results/ e2e/junit.xml retention-days: 14 build: name: Build Package runs-on: ubuntu-latest timeout-minutes: 15 needs: [lint, test] steps: - uses: actions/checkout@v7 - name: Set up Python uses: actions/setup-python@v7 with: python-version-file: ".python-version" cache: pip - name: Install build tools run: | python -m pip install --upgrade pip pip install build - name: Build package run: python -m build - name: Upload artifacts uses: actions/upload-artifact@v7 with: name: dist path: dist/ summary: name: Summary runs-on: ubuntu-latest timeout-minutes: 5 needs: [lint, frontend, test, e2e, build] if: ${{ !cancelled() }} steps: - uses: actions/checkout@v7 - name: Set up Python uses: actions/setup-python@v7 with: python-version-file: ".python-version" - name: Download artifacts uses: actions/download-artifact@v8 continue-on-error: true with: path: results - name: Render CI summary env: NEEDS_JSON: ${{ toJson(needs) }} run: python .github/scripts/ci_summary.py