name: modified_scripts
on: [pull_request]
jobs:
  discover_modified_scripts:
    runs-on: ubuntu-latest
    outputs:
      versions: ${{steps.modified-versions.outputs.versions}}
      versions_cpython_only: ${{steps.modified-versions.outputs.versions_cpython_only}}
      versions_macos_build_exclude: ${{steps.modified-versions.outputs.versions_macos_build_exclude}}
    steps:
      - uses: actions/checkout@v6
      - run: git fetch origin "$GITHUB_BASE_REF"
      - shell: bash
        run: >
          versions=$(git diff "origin/$GITHUB_BASE_REF" --name-only -z
          | perl -ne 'BEGIN {$\="\n";$/="\0";} chomp;
            if (/^plugins\/python-build\/share\/python-build\/(?:([^\/]+)|patches\/([^\/]+)\/.*)$/ and -e $& )
                { print $1.$2; }' \
          | sort -u);
          EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64);
          echo "versions<<$EOF" >> $GITHUB_ENV;
          echo "$versions" >> $GITHUB_ENV;
          echo "$EOF" >> $GITHUB_ENV;
          
          versions_cpython_only=$(grep -Ee '^[[:digit:]]' <<<"$versions")
          EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64);
          echo "versions_cpython_only<<$EOF" >> $GITHUB_ENV;
          echo "$versions_cpython_only" >> $GITHUB_ENV;
          echo "$EOF" >> $GITHUB_ENV;
      - run: pip install packaging
      - name: Build exclusions JSON
        shell: python
        run: |
          import os
          import json
          import random
          import re
          import subprocess
          
          import packaging.version
          
          result=[]
          
          for line in os.environ['versions'].splitlines():
            if m:=re.match(r'([^-]+)-(\d+\.\d+)-(\d+\.\d+.\d+)', line):
              name, version = m.group(1), packaging.version.Version(m.group(3))
              
              # Miniconda dropped MacOS x64 support
              if (name == 'miniconda3' and version >= packaging.version.Version('25.9.1')):
                result.append({'os':'macos-15-intel','python-version':line})
            
            if m:=re.match(r'([^-]+)-(\d+\.\d+)', line):
              name, version = m.group(1), packaging.version.Version(m.group(2))
              
              # Anaconda dropped MacOS x64 support
              if name == 'anaconda3' and version >= packaging.version.Version('2025.12'):
                result.append({'os':'macos-15-intel','python-version':line})
          
            if m:=re.match(r'graalpy-(community-)?-(\d+\.\d+.\d+)', line):
              version = packaging.version.Version(m.group(2))
              
              # GraalPy dropped MacOS x64 support
              if version >= packaging.version.Version('25.0.2'):
                result.append({'os':'macos-15-intel','python-version':line})
              
          
          EOF = str(random.getrandbits(15*8))
          
          with open(os.environ['GITHUB_ENV'],'w') as f:
            f.write(f"versions_macos_build_exclude_json<<{EOF}\n")
            json.dump(result, f)
            f.write(f'\n{EOF}\n')
          
      - id: modified-versions
        run: |
          echo "versions=`echo "${{ env.versions }}" | jq -R . | jq -sc .`" >> $GITHUB_OUTPUT
          echo "versions_cpython_only=`echo "${{ env.versions_cpython_only }}" | jq -R . | jq -sc .`" >> $GITHUB_OUTPUT
          echo 'versions_macos_build_exclude=${{ env.versions_macos_build_exclude_json }}' >> $GITHUB_OUTPUT
  macos_build:
    needs: discover_modified_scripts
    if: needs.discover_modified_scripts.outputs.versions != '[""]'
    strategy:
      fail-fast: false
      matrix:
        python-version: ${{fromJson(needs.discover_modified_scripts.outputs.versions)}}
        os:
          - macos-14
          - macos-15
          - macos-15-intel
          - macos-26
        exclude: ${{fromJson(needs.discover_modified_scripts.outputs.versions_macos_build_exclude)}}
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v6
      - run: |
          #envvars
          export PYENV_ROOT="$GITHUB_WORKSPACE"
          echo "PYENV_ROOT=$PYENV_ROOT" >> $GITHUB_ENV
          echo "$PYENV_ROOT/shims:$PYENV_ROOT/bin" >> $GITHUB_PATH
      - run: |
          #prerequisites
          brew install openssl readline sqlite3 xz zlib
          if [[ "${{ matrix.python-version }}" =~ pypy.*-(src|dev) ]]; then
            export PYENV_BOOTSTRAP_VERSION=pypy2.7-7
            echo "PYENV_BOOTSTRAP_VERSION=$PYENV_BOOTSTRAP_VERSION" >> $GITHUB_ENV
            pyenv install $PYENV_BOOTSTRAP_VERSION
          fi
      - run: |
          #build
          pyenv --debug install ${{ matrix.python-version }} && rc=$? || rc=$?
          if [[ $rc -ne 0 ]]; then echo config.log:; cat $TMPDIR/python-build*/*/config.log; false; fi
          pyenv global ${{ matrix.python-version }}
      # Micropython doesn't support --version
      - run: |
          #print version
          if [[ "${{ matrix.python-version }}" == "micropython-"* ]]; then
            python -c 'import sys; print(sys.version)'
          else
            python --version
            python -m pip --version
          fi
      # Micropython doesn't support sys.executable, os.path, older versions even os
      - env:
          EXPECTED_PYTHON: ${{ matrix.python-version }}
        run: |
          #check
          if [[ "${{ matrix.python-version }}" == "micropython-"* ]]; then
            [[ $(pyenv which python) == "${{ env.PYENV_ROOT }}/versions/${{ matrix.python-version }}/bin/python" ]] || exit 1
            python -c 'import sys; assert sys.implementation.name == "micropython"'
          else
            python -c 'if True:
            import os, sys, os.path
            correct_dir = os.path.join(
              os.environ["PYENV_ROOT"],
              "versions",
              os.environ["EXPECTED_PYTHON"],
              "bin")
            assert os.path.dirname(sys.executable) == correct_dir'
          fi
      # bundled executables in some Anaconda releases cause the post-run step to hang in MacOS
      - run: |
          pyenv global system
          rm -f "$(pyenv root)"/shims/*
          

  macos_build_bundled_dependencies:
    needs: discover_modified_scripts
    if: needs.discover_modified_scripts.outputs.versions_cpython_only != '[""]'
    strategy:
      fail-fast: false
      matrix:
        python-version: ${{fromJson(needs.discover_modified_scripts.outputs.versions_cpython_only)}}
        os: ["macos-14", "macos-15", "macos-15-intel"]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v6
      - run: |
          #envvars
          export PYENV_ROOT="$GITHUB_WORKSPACE"
          echo "PYENV_ROOT=$PYENV_ROOT" >> $GITHUB_ENV
          echo "$PYENV_ROOT/shims:$PYENV_ROOT/bin" >> $GITHUB_PATH
      - run: |
          #prerequisites
          brew install sqlite3 xz zlib
          "$GITHUB_WORKSPACE/.github/workflows/scripts/brew-uninstall-cascade.sh" openssl@3 openssl@1.1 readline
          if [[ "${{ matrix.python-version }}" =~ pypy.*-(src|dev) ]]; then
            export PYENV_BOOTSTRAP_VERSION=pypy2.7-7
            echo "PYENV_BOOTSTRAP_VERSION=$PYENV_BOOTSTRAP_VERSION" >> $GITHUB_ENV
            pyenv install $PYENV_BOOTSTRAP_VERSION
          fi
      - run: |
          #build
          pyenv --debug install ${{ matrix.python-version }} && rc=$? || rc=$?
          if [[ $rc -ne 0 ]]; then echo config.log:; cat $TMPDIR/python-build*/*/config.log; false; fi
          pyenv global ${{ matrix.python-version }}
      - run: |
          #print version
          python --version
          python -m pip --version
      - env:
          EXPECTED_PYTHON: ${{ matrix.python-version }}
        run: |
          #check
          python -c '
          import os, sys, os.path
          correct_dir = os.path.join(
            os.environ["PYENV_ROOT"],
            "versions",
            os.environ["EXPECTED_PYTHON"],
            "bin")
          assert os.path.dirname(sys.executable) == correct_dir'

  ubuntu_build:
    needs: discover_modified_scripts
    if: needs.discover_modified_scripts.outputs.versions != '[""]'
    strategy:
      fail-fast: false
      matrix:
        python-version: ${{fromJson(needs.discover_modified_scripts.outputs.versions)}}
        os:
          - ubuntu-22.04
          - ubuntu-24.04
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v6
      - run: |
          #envvars
          export PYENV_ROOT="$GITHUB_WORKSPACE"
          echo "PYENV_ROOT=$PYENV_ROOT" >> $GITHUB_ENV
          echo "$PYENV_ROOT/shims:$PYENV_ROOT/bin" >> $GITHUB_PATH
      - run: |
          #prerequisites
          sudo apt-get update -q; sudo apt-get install -yq make build-essential \
            libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev \
            curl llvm libncurses5-dev libncursesw5-dev \
            xz-utils tk-dev libffi-dev liblzma-dev
          if [[ "${{ matrix.python-version }}" =~ pypy.*-(src|dev) ]]; then
            export PYENV_BOOTSTRAP_VERSION=pypy2.7-7
            echo "PYENV_BOOTSTRAP_VERSION=$PYENV_BOOTSTRAP_VERSION" >> $GITHUB_ENV
            pyenv install $PYENV_BOOTSTRAP_VERSION
          fi
      - run: |
          #build
          pyenv --debug install ${{ matrix.python-version }} && rc=$? || rc=$?
          if [[ $rc -ne 0 ]]; then echo config.log:; cat $TMPDIR/python-build*/*/config.log; false; fi
          pyenv global ${{ matrix.python-version }}
      # Micropython doesn't support --version
      - run: |
          #print version
          if [[ "${{ matrix.python-version }}" == "micropython-"* ]]; then
            python -c 'import sys; print(sys.version)'
          else
            python --version
            python -m pip --version
          fi
      # Micropython doesn't support sys.executable, os.path, older versions even os
      - env:
          EXPECTED_PYTHON: ${{ matrix.python-version }}
        run: |
          #check
          if [[ "${{ matrix.python-version }}" == "micropython-"* ]]; then
            [[ $(pyenv which python) == "${{ env.PYENV_ROOT }}/versions/${{ matrix.python-version }}/bin/python" ]] || exit 1
            python -c 'import sys; assert sys.implementation.name == "micropython"'
          else
            python -c 'if True:
            import os, sys, os.path
            correct_dir = os.path.join(
              os.environ["PYENV_ROOT"],
              "versions",
              os.environ["EXPECTED_PYTHON"],
              "bin")
            assert os.path.dirname(sys.executable) == correct_dir'
          fi
      # bundled executables in some Anaconda releases cause the post-run step to break
      - run: |
          pyenv global system
          rm -f "$(pyenv root)"/shims/*
  ubuntu_build_tar_gz:
    needs: discover_modified_scripts
    if: needs.discover_modified_scripts.outputs.versions_cpython_only != '[""]'
    strategy:
      fail-fast: false
      matrix:
        python-version: ${{fromJson(needs.discover_modified_scripts.outputs.versions_cpython_only)}}
        os: ["ubuntu-latest"]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v6
      - run: |
          #envvars
          export PYENV_ROOT="$GITHUB_WORKSPACE"
          echo "PYENV_ROOT=$PYENV_ROOT" >> $GITHUB_ENV
          echo "$PYENV_ROOT/shims:$PYENV_ROOT/bin" >> $GITHUB_PATH
          echo "_PYTHON_BUILD_FORCE_SKIP_XZ=1" >> $GITHUB_PATH
      - run: |
          #prerequisites
          sudo apt-get update -q; sudo apt-get install -yq make build-essential \
            libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev \
            curl llvm libncurses5-dev libncursesw5-dev \
            xz-utils tk-dev libffi-dev liblzma-dev
          if [[ "${{ matrix.python-version }}" =~ pypy.*-(src|dev) ]]; then
            export PYENV_BOOTSTRAP_VERSION=pypy2.7-7
            echo "PYENV_BOOTSTRAP_VERSION=$PYENV_BOOTSTRAP_VERSION" >> $GITHUB_ENV
            pyenv install $PYENV_BOOTSTRAP_VERSION
          fi
      - run: |
          #build
          pyenv --debug install ${{ matrix.python-version }} && rc=$? || rc=$?
          if [[ $rc -ne 0 ]]; then echo config.log:; cat $TMPDIR/python-build*/*/config.log; false; fi
          pyenv global ${{ matrix.python-version }}
      - run: |
          #print version
          python --version
          python -m pip --version
      - env:
          EXPECTED_PYTHON: ${{ matrix.python-version }}
        run: |
          #check
          python -c '
          import os, sys, os.path
          correct_dir = os.path.join(
            os.environ["PYENV_ROOT"],
            "versions",
            os.environ["EXPECTED_PYTHON"],
            "bin")
          assert os.path.dirname(sys.executable) == correct_dir'
