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

env:
  RUST_VERSION: 1.87.0

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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Install Rust
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # master
        with:
          toolchain: ${{ env.RUST_VERSION }}
      - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1

      - uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0
        with:
          python-version: "3.x"
          extras: "all"
          poetry-version: "2.2.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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - run: sudo apt-get -qq install xmlsec1

      - name: Install Rust
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # master
        with:
          toolchain: ${{ env.RUST_VERSION }}
      - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1

      - uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0
        with:
          python-version: "3.x"
          extras: "all test"
          poetry-version: "2.2.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 bookworm because that's what Debian oldstable is at the time of writing.
      # 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:bookworm
      volumes:
        - ${{ github.workspace }}:/src

    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Install Rust
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # master
        with:
          toolchain: ${{ env.RUST_VERSION }}
      - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1

      - 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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        if: ${{ always() }}
        with:
          name: Sytest Logs - ${{ job.status }} - (${{ join(matrix.*, ', ') }})
          path: |
            /logs/results.tap
            /logs/**/*.log*

  complement:
    uses: ./.github/workflows/complement_tests.yml
    needs: check_repo
    if: "!failure() && !cancelled() && needs.check_repo.outputs.should_run_workflow == 'true'"
    with:
      use_twisted_trunk: true

  # 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.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
