name: CI

on: [ push, pull_request, workflow_dispatch ]

permissions:
  contents: read

jobs:
  lint-pr:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          persist-credentials: false
      - uses: actions/setup-python@v4
        with:
          python-version-file: .github/python-version.txt
      - uses: TrueBrain/actions-flake8@c2deca24d388aa5aedd6478332aa9df4600b5eac # v2.1
        # mirrored at https://github.com/mitmproxy/mitmproxy/settings/actions
  lint-local:
    if: github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          persist-credentials: false
      - uses: actions/setup-python@v4
        with:
          python-version-file: .github/python-version.txt
      - run: pip install tox
      - run: tox -e flake8
  filename-matching:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          persist-credentials: false
      - uses: actions/setup-python@v4
        with:
          python-version-file: .github/python-version.txt
      - run: pip install tox
      - run: tox -e filename_matching
  mypy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          persist-credentials: false
      - uses: actions/setup-python@v4
        with:
          python-version-file: .github/python-version.txt
      - run: pip install tox
      - run: tox -e mypy
  individual-coverage:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          persist-credentials: false
          fetch-depth: 0
      - uses: actions/setup-python@v4
        with:
          python-version-file: .github/python-version.txt
      - run: pip install tox
      - run: tox -e individual_coverage
  test:
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-latest
            py: "3.11"
          - os: windows-latest
            py: "3.11"
          - os: macos-latest
            py: "3.11"
          - os: ubuntu-latest
            py: "3.10"
          - os: ubuntu-latest
            py: "3.9"
    runs-on: ${{ matrix.os }}
    steps:
      - run: printenv
      - uses: actions/checkout@v3
        with:
          persist-credentials: false
          fetch-depth: 0
      - uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.py }}
      - run: pip install tox
      - run: tox -e py
        if: matrix.os != 'ubuntu-latest'
      - name: Run tox -e py (without internet)
        run: |
          # install dependencies (requires internet connectivity)
          tox -e py --notest  
          # run tests with loopback only. We need to sudo for unshare, which means we need an absolute path for tox.
          sudo unshare --net -- sh -c "ip link set lo up; $(which tox) -e py"
        if: matrix.os == 'ubuntu-latest'
      - uses: codecov/codecov-action@a1ed4b322b4b38cb846afb5a0ebfa17086917d27
        # mirrored below and at https://github.com/mitmproxy/mitmproxy/settings/actions
        with:
          file: ./coverage.xml
          name: ${{ matrix.os }}

  build:
    strategy:
      fail-fast: false
      matrix:
        include:
          - image: macos-11
            platform: macos
          - image: windows-2019
            platform: windows
          - image: ubuntu-20.04  # Oldest available version so we get oldest glibc possible.
            platform: linux
    runs-on: ${{ matrix.image }}
    env:
      CI_BUILD_KEY: ${{ secrets.CI_BUILD_KEY }}
    steps:
      - uses: actions/checkout@v3
        with:
          persist-credentials: false
          fetch-depth: 0
      - uses: actions/setup-python@v4
        with:
          python-version-file: .github/python-version.txt
      - if: matrix.platform == 'windows'
        uses: actions/cache@v3
        with:
          path: release/installbuilder/setup
          key: installbuilder
      - run: pip install -e .[dev]
      - run: python -u release/build.py standalone-binaries
      - if: matrix.platform == 'linux'
        run: python -u release/build.py --dirty wheel
      - if: matrix.platform == 'windows' && github.repository == 'mitmproxy/mitmproxy' && github.event_name == 'push'
        run: python -u release/build.py --dirty installbuilder-installer msix-installer
      - uses: actions/upload-artifact@v3
        with:
          # artifacts must have different names, see https://github.com/actions/upload-artifact/issues/24
          name: binaries.${{ matrix.platform }}
          path: |
            release/dist

  test-web-ui:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          persist-credentials: false
      - run: git rev-parse --abbrev-ref HEAD
      - uses: actions/setup-node@v3
        with:
          node-version-file: .github/node-version.txt
      - name: Cache Node.js modules
        uses: actions/cache@v3
        with:
          # npm cache files are stored in `~/.npm` on Linux/macOS
          path: ~/.npm
          key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.OS }}-node-
            ${{ runner.OS }}-
      - working-directory: ./web
        run: npm ci
      - working-directory: ./web
        run: npm test
      - uses: codecov/codecov-action@a1ed4b322b4b38cb846afb5a0ebfa17086917d27
        # mirrored above and at https://github.com/mitmproxy/mitmproxy/settings/actions
        with:
          file: ./web/coverage/coverage-final.json
          name: web

  docs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          persist-credentials: false
      - uses: actions/setup-python@v4
        with:
          python-version-file: .github/python-version.txt
      - run: |
          wget -q https://github.com/gohugoio/hugo/releases/download/v0.92.1/hugo_extended_0.92.1_Linux-64bit.deb
          echo "a9440adfd3ecce40089def287dee4e42ffae252ba08c77d1ac575b880a079ce6 hugo_extended_0.92.1_Linux-64bit.deb" | sha256sum -c
          sudo dpkg -i hugo*.deb
      - run: pip install -e .[dev]
      - run: ./docs/build.py
      - uses: actions/upload-artifact@v3
        with:
          name: docs
          path: docs/public
      # For releases, also build the archive version of the docs.
      - if: startsWith(github.ref, 'refs/tags/')
        run: ./docs/build.py
        env:
          DOCS_ARCHIVE: true
      - if: startsWith(github.ref, 'refs/tags/')
        uses: actions/upload-artifact@v3
        with:
          name: docs-archive
          path: docs/public

  # Separate from everything else because slow.
  build-and-deploy-docker:
    if: github.repository == 'mitmproxy/mitmproxy' && (
      github.ref == 'refs/heads/main'
      || github.ref == 'refs/heads/citest'
      || startsWith(github.ref, 'refs/tags/')
      )
    environment: deploy-docker
    needs:
      - test
      - test-web-ui
      - build
      - docs
    runs-on: ubuntu-latest
    env:
      DOCKER_USERNAME: mitmbot
      DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
    steps:
      - uses: actions/checkout@v3
        with:
          persist-credentials: false
      - uses: actions/setup-python@v4
        with:
          python-version-file: .github/python-version.txt
      - uses: actions/download-artifact@v2
        with:
          name: binaries.linux
          path: release/dist
      - uses: docker/setup-qemu-action@27d0a4f181a40b142cce983c5393082c365d1480 # v1.2.0
      - uses: docker/setup-buildx-action@b1f1f719c7cd5364be7c82e366366da322d01f7c # v1.6.0
      - run: python release/build-and-deploy-docker.py

  deploy:
    # This action has access to our AWS keys, so we are extra careful here.
    # In particular, we don't blindly `pip install` anything to minimize the risk of supply chain attacks.
    if: github.repository == 'mitmproxy/mitmproxy' && (startsWith(github.ref, 'refs/heads/') || startsWith(github.ref, 'refs/tags/'))
    environment: ${{ (github.ref == 'refs/heads/citest' || startsWith(github.ref, 'refs/tags/')) && 'deploy-release' || 'deploy-snapshot' }}
    needs:
      - test
      - test-web-ui
      - build
      - docs
    runs-on: ubuntu-latest
    env:
      # PyPI and MSFT keys are only available for the deploy-release environment
      # The AWS access key for snapshots is scoped to branches/* as well.
      TWINE_USERNAME: __token__
      TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      AWS_DEFAULT_REGION: us-west-2
      MSFT_APP_ID: 9NWNDLQMNZD7
      MSFT_TENANT_ID: ${{ secrets.MSFT_TENANT_ID }}
      MSFT_CLIENT_ID: ${{ secrets.MSFT_CLIENT_ID }}
      MSFT_CLIENT_SECRET: ${{ secrets.MSFT_CLIENT_SECRET }}
    steps:
      - uses: actions/checkout@v3
        with:
          persist-credentials: false
      - uses: actions/setup-python@v4
        with:
          python-version-file: .github/python-version.txt
      - run: sudo apt-get update
      - run: sudo apt-get install -y awscli
      - if: startsWith(github.ref, 'refs/tags/')
        run: sudo apt-get install -y twine

      - uses: actions/download-artifact@v3
        with:
          name: docs
          path: docs/public
      - if: startsWith(github.ref, 'refs/tags/')
        uses: actions/download-artifact@v3
        with:
          name: docs-archive
          path: docs/archive
      - uses: actions/download-artifact@v3
        with:
          name: binaries.windows
          path: release/dist
      - uses: actions/download-artifact@v3
        with:
          name: binaries.linux
          path: release/dist
      - uses: actions/download-artifact@v3
        with:
          name: binaries.macos
          path: release/dist
      - run: ls docs/public
      - run: ls release/dist

      - run: ./release/deploy.py

      - name: Deploy to Microsoft Store (test flight)
        if: github.ref == 'refs/heads/citest'
        run: ./release/deploy-microsoft-store.py release/dist/*.msix
        env:
          MSFT_APP_FLIGHT: 174ca570-8cae-4444-9858-c07293f1f13a
      - name: Deploy to Microsoft Store
        if: startsWith(github.ref, 'refs/tags/')
        run: ./release/deploy-microsoft-store.py release/dist/*.msix
