name: Python package

on:
  push:
    branches-ignore:
      - 'dependabot/**'
      - 'gh-pages'
    tags:
      - "[0-9]+.[0-9]+.[0-9]+"  # Canonical versioned tags
      - "[0-9]+.[0-9]+.[0-9]+.post[0-9]+"  # Canonical rebuild tags
  pull_request:
    paths:
      - "urwid/**"
      - "source/**"
      - "pyproject.toml"
      - "MANIFEST.in"
      - "README.rst"
      - "COPYING"
      - "tests/**"
      - "examples/**"
      - ".coveralls.yml"
      - ".github/workflows/pythonpackage.yml"

concurrency:
  group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}"
  cancel-in-progress: true

jobs:
  Ruff-format:
    name: Validate formatting
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          python-version: '3.x'
          cache: 'pip'
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install --upgrade -r ruff-requirements.txt
      - name: Check code style with ruff
        run: |
          ruff format --check .

  Ruff:
    name: Check with Ruff
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          python-version: '3.x'
          cache: 'pip'
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install --upgrade -r ruff-requirements.txt
      - name: Lint with ruff
        run: |
          ruff check --output-format github .

  PyLint:
    name: Check with pylint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - name: Install Ubuntu dependencies
        run: |
          sudo apt-get -qq update
          sudo apt-get install -y python3-dev python3-gi python3-gi-cairo
          sudo apt-get install -y gobject-introspection libgirepository-2.0-dev libcairo2-dev
      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          python-version: '3.x'
          cache: 'pip'
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r test_requirements.txt PyGObject
          pip install --upgrade -r pylint-requirements.txt
      - name: Install package for test
        run: pip install -e .
      - name: Lint with pylint
        run: pylint --output-format=github urwid

  Test:
    needs: [ Ruff-format, Ruff, PyLint ]
    runs-on: ${{ matrix.os }}
    strategy:
      max-parallel: 6
      matrix:
        os: [ "ubuntu-latest", "windows-latest" ]
        # , "macos-latest"
        # enable macOS only if OS specific branch will be added
        python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13", "3.14" ]
        exclude:
          - os: "windows-latest"
            python-version: "3.14"

    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0  # need for setuptools_scm
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v6
        with:
          python-version: ${{ matrix.python-version }}
          allow-prereleases: true
          cache: 'pip'
      - name: Install Ubuntu dependencies
        if: runner.os == 'Linux'
        run: |
          sudo apt-get -qq update
          sudo apt-get install -y python3-dev python3-gi python3-gi-cairo
          sudo apt-get install -y gobject-introspection libgirepository-2.0-dev libcairo2-dev
      - name: Install Mac OS X dependencies
        if: runner.os == 'macOS'
        run: |
          brew install gtk+3 gobject-introspection gtk-mac-integration
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip wheel
          pip install -r test_requirements.txt
      - name: Install PyGObject
        if: runner.os == 'Linux' || runner.os == 'macOS'
        run: pip install PyGObject
      - name: Install package for test
        run: pip install -e .
      - name: Test
        run: |
          coverage run -m unittest discover -s tests -v
          coverage report
          coverage xml
      - name: Coveralls Parallel
        uses: coverallsapp/github-action@v2
        with:
          flag-name: run-${{ matrix.python-version }}-${{ matrix.os }}"
          parallel: true
          file: coverage.xml

  UploadCoverage:
    name: Upload coverage to Coveralls
    needs: [ Test ]
    if: ${{ always() }}
    runs-on: ubuntu-latest
    steps:
      - name: Coveralls Finished
        uses: coverallsapp/github-action@v2
        with:
          parallel-finished: true

  build:
    name: Build distribution
    needs: [ Test, Ruff-format, Ruff, PyLint ]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0  # need for setuptools_scm

      - uses: actions/setup-python@v6
        with:
          python-version: "3.x"

      - name: Install dependencies
        run: pip install -U build

      - name: Build dist
        run: python -m build

      - uses: actions/upload-artifact@v5
        with:
          path: dist/*.tar.gz
          name: built-sdist
          retention-days: 3

      - uses: actions/upload-artifact@v5
        with:
          path: dist/*.whl
          name: built-bdist
          retention-days: 3

  Metadata:
    name: Validate metadata
    runs-on: ubuntu-latest
    needs: [ build ]
    steps:
      - uses: actions/checkout@v6
      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          python-version: '3.x'
          cache: 'pip'
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install --upgrade twine
      - uses: actions/download-artifact@v6
        with:
          # unpacks default artifact into dist/
          # if `name: wheels` is omitted, the action will create extra parent dir
          pattern: built-*
          merge-multiple: true
          path: dist

      - name: Validate metadata
        run: |
          twine check dist/*

  upload_pypi:
    needs: [ build, Metadata ]
    # upload to PyPI on every tag
    if: github.event_name == 'push' && github.ref_type == 'tag' && github.repository == 'urwid/urwid'
    # alternatively, to publish when a GitHub Release is created, use the following rule:
    # if: github.event_name == 'release' && github.event.action == 'published'
    runs-on: ubuntu-latest
    environment:
      name: pypi
      url: https://pypi.org/p/urwid
    permissions:
      id-token: write  # IMPORTANT: this permission is mandatory for trusted publishing
    steps:
      - uses: actions/download-artifact@v6
        with:
          pattern: built-*
          merge-multiple: true
          path: dist

      - name: Publish package distributions to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
