name: Code coverage

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
    types:
      - opened
      - reopened
      - synchronize
      - ready_for_review

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

env:
  CARGO_TERM_COLOR: always
  # without matrix_sdk=trace, expressions in `trace!` fields are not evaluated
  # when the `trace!` statement is hit, and thus not covered
  RUST_LOG: info,matrix_sdk=trace

jobs:
  code_coverage:
    name: Code Coverage
    runs-on: "ubuntu-latest"
    if: github.event_name == 'push' || !github.event.pull_request.draft

    # run several docker containers with the same networking stack so the hostname 'postgres'
    # maps to the postgres container, etc.
    services:
      # sliding sync needs a postgres container
      postgres:
        # Docker Hub image
        image: postgres
        # Provide the password for postgres
        env:
          POSTGRES_PASSWORD: postgres
          POSTGRES_USER: postgres
          POSTGRES_DB: syncv3
        # Set health checks to wait until postgres has started
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          # Maps tcp port 5432 on service container to the host
          - 5432:5432
      # run sliding sync and point it at the postgres container and synapse container.
      # the postgres container needs to be above this to make sure it has started prior to this service.
      slidingsync:
        image: "ghcr.io/matrix-org/sliding-sync:v0.99.11" # keep in sync with ./ci.yml
        env:
          SYNCV3_SERVER: "http://synapse:8008"
          SYNCV3_SECRET: "SUPER_CI_SECRET"
          SYNCV3_BINDADDR: ":8118"
          SYNCV3_DB: "user=postgres password=postgres dbname=syncv3 sslmode=disable host=postgres"
        ports:
          - 8118:8118
      # tests need a synapse: this is a service and not michaelkaye/setup-matrix-synapse@main as the
      # latter does not provide networking for services to communicate with it.
      synapse:
        image: ghcr.io/matrix-org/synapse-service:v1.94.0 # keep in sync with ./ci.yml
        env:
            SYNAPSE_COMPLEMENT_DATABASE: sqlite
            SERVER_NAME: synapse
        ports:
            - 8008:8008

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          ref: ${{ github.event.pull_request.head.sha }}

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable

      # Cargo config can screw with caching and is only used for alias config
      # and extra lints, which we don't care about here
      - name: Delete cargo config
        run: rm .cargo/config.toml

      - name: Load cache
        uses: Swatinem/rust-cache@v2
        with:
          save-if: ${{ github.ref == 'refs/heads/main' }}

      - name: Install tarpaulin
        uses: taiki-e/install-action@v2
        with:
          tool: cargo-tarpaulin

      # set up backend for integration tests
      - uses: actions/setup-python@v4
        with:
          python-version: 3.8

      - name: Run tarpaulin
        run: |
          rustup run stable cargo tarpaulin \
            --skip-clean --profile cov --out xml \
            --features experimental-widgets,testing
        env:
          CARGO_PROFILE_COV_INHERITS: 'dev'
          CARGO_PROFILE_COV_DEBUG: 'false'
          HOMESERVER_URL: "http://localhost:8008"
          HOMESERVER_DOMAIN: "synapse"
          SLIDING_SYNC_PROXY_URL: "http://localhost:8118"

      - name: Upload to codecov.io
        uses: codecov/codecov-action@v3
        with:
          # Work around frequent upload errors, for runs inside the main repo (not PRs from forks).
          # Otherwise not required for public repos.
          token: ${{ secrets.CODECOV_UPLOAD_TOKEN }}
          # The upload sometimes fails due to https://github.com/codecov/codecov-action/issues/837.
          # To make sure that the failure gets flagged clearly in the UI, fail the action.
          fail_ci_if_error: true
