name: Twisted Trunk

on:
  schedule:
    - cron: 0 8 * * *

  workflow_dispatch:
    # NB: inputs are only present when this workflow is dispatched manually.
    # (The default below is the default field value in the form to trigger
    # a manual dispatch). Otherwise the inputs will evaluate to null.
    inputs:
      twisted_ref:
        description: Commit, branch or tag to checkout from upstream Twisted.
        required: false
        default: 'trunk'
        type: string


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

jobs:
  check_repo:
    # Prevent this workflow from running on any fork of Synapse other than element-hq/synapse, as it is
    # only useful to the Synapse core team.
    # All other workflow steps depend on this one, thus if 'should_run_workflow' is not 'true', the rest
    # of the workflow will be skipped as well.
    if: github.repository == 'element-hq/synapse'
    runs-on: ubuntu-latest
    outputs:
      should_run_workflow: ${{ steps.check_condition.outputs.should_run_workflow }}
    steps:
      - id: check_condition
        run: echo "should_run_workflow=${{ github.repository == 'element-hq/synapse' }}" >> "$GITHUB_OUTPUT"

  mypy:
    needs: check_repo
    if: needs.check_repo.outputs.should_run_workflow == 'true'
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

      - name: Install Rust
        uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable (rust 1.85.1)
      - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8

      - uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0
        with:
          python-version: "3.x"
          extras: "all"
          poetry-version: "2.1.1"
      - run: |
          poetry remove twisted
          poetry add --extras tls git+https://github.com/twisted/twisted.git#${{ inputs.twisted_ref || 'trunk' }}
          poetry install --no-interaction --extras "all test"
      - name: Remove unhelpful options from mypy config
        run: sed -e '/warn_unused_ignores = True/d' -e '/warn_redundant_casts = True/d' -i mypy.ini
      - run: poetry run mypy

  trial:
    needs: check_repo
    if: needs.check_repo.outputs.should_run_workflow == 'true'
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
      - run: sudo apt-get -qq install xmlsec1

      - name: Install Rust
        uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable (rust 1.85.1)
      - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8

      - uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0
        with:
          python-version: "3.x"
          extras: "all test"
          poetry-version: "2.1.1"
      - run: |
          poetry remove twisted
          poetry add --extras tls git+https://github.com/twisted/twisted.git#trunk
          poetry install --no-interaction --extras "all test"
      - run: poetry run trial --jobs 2 tests

      - name: Dump logs
        # Logs are most useful when the command fails, always include them.
        if: ${{ always() }}
        # Note: Dumps to workflow logs instead of using actions/upload-artifact
        #       This keeps logs colocated with failing jobs
        #       It also ignores find's exit code; this is a best effort affair
        run: >-
          find _trial_temp -name '*.log'
          -exec echo "::group::{}" \;
          -exec cat {} \;
          -exec echo "::endgroup::" \;
          || true

  sytest:
    needs: check_repo
    if: needs.check_repo.outputs.should_run_workflow == 'true'
    runs-on: ubuntu-latest
    container:
      # We're using debian:bullseye because it uses Python 3.9 which is our minimum supported Python version.
      # This job is a canary to warn us about unreleased twisted changes that would cause problems for us if
      # they were to be released immediately. For simplicity's sake (and to save CI runners) we use the oldest
      # version, assuming that any incompatibilities on newer versions would also be present on the oldest.
      image: matrixdotorg/sytest-synapse:bullseye
      volumes:
        - ${{ github.workspace }}:/src

    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

      - name: Install Rust
        uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable (rust 1.85.1)
      - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8

      - name: Patch dependencies
        # Note: The poetry commands want to create a virtualenv in /src/.venv/,
        #       but the sytest-synapse container expects it to be in /venv/.
        #       We symlink it before running poetry so that poetry actually
        #       ends up installing to `/venv`.
        run: |
          ln -s -T /venv /src/.venv
          poetry remove twisted
          poetry add --extras tls git+https://github.com/twisted/twisted.git#trunk
          poetry install --no-interaction --extras "all test"
        working-directory: /src
      - name: Run SyTest
        run: /bootstrap.sh synapse
        working-directory: /src
        env:
          # Use offline mode to avoid reinstalling the pinned version of
          # twisted.
          OFFLINE: 1
      - name: Summarise results.tap
        if: ${{ always() }}
        run: /sytest/scripts/tap_to_gha.pl /logs/results.tap
      - name: Upload SyTest logs
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
        if: ${{ always() }}
        with:
          name: Sytest Logs - ${{ job.status }} - (${{ join(matrix.*, ', ') }})
          path: |
            /logs/results.tap
            /logs/**/*.log*

  complement:
    needs: check_repo
    if: "!failure() && !cancelled() && needs.check_repo.outputs.should_run_workflow == 'true'"
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        include:
          - arrangement: monolith
            database: SQLite

          - arrangement: monolith
            database: Postgres

          - arrangement: workers
            database: Postgres

    steps:
      - name: Run actions/checkout@v4 for synapse
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          path: synapse

      - name: Prepare Complement's Prerequisites
        run: synapse/.ci/scripts/setup_complement_prerequisites.sh

      - uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
        with:
          cache-dependency-path: complement/go.sum
          go-version-file: complement/go.mod

      # This step is specific to the 'Twisted trunk' test run:
      - name: Patch dependencies
        run: |
          set -x
          DEBIAN_FRONTEND=noninteractive sudo apt-get install -yqq python3 pipx
          pipx install poetry==2.1.1

          poetry remove -n twisted
          poetry add -n --extras tls git+https://github.com/twisted/twisted.git#trunk
          poetry lock
        working-directory: synapse

      - run: |
          set -o pipefail
          TEST_ONLY_SKIP_DEP_HASH_VERIFICATION=1 POSTGRES=${{ (matrix.database == 'Postgres') && 1 || '' }} WORKERS=${{ (matrix.arrangement == 'workers') && 1 || '' }} COMPLEMENT_DIR=`pwd`/complement synapse/scripts-dev/complement.sh -json 2>&1 | synapse/.ci/scripts/gotestfmt
        shell: bash
        name: Run Complement Tests

  # open an issue if the build fails, so we know about it.
  open-issue:
    if: failure() && needs.check_repo.outputs.should_run_workflow == 'true'
    needs:
      - mypy
      - trial
      - sytest
      - complement

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
      - uses: JasonEtco/create-an-issue@1b14a70e4d8dc185e5cc76d3bec9eab20257b2c5 # v2.9.2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          update_existing: true
          filename: .ci/twisted_trunk_build_failed_issue_template.md
