diff --git a/.github/workflows/pip.yml b/.github/workflows/pip.yml index f1ed4d8b..7f5733a6 100644 --- a/.github/workflows/pip.yml +++ b/.github/workflows/pip.yml @@ -25,19 +25,23 @@ concurrency: cancel-in-progress: true jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 permissions: contents: read + outputs: + package-version: ${{ steps.build.outputs.PACKAGE_VERSION }} steps: - name: Checkout sources uses: actions/checkout@v4 with: - # Get Git tags so that versioneer can function correctly + # Get Git tags # See issue https://github.com/actions/checkout/issues/701 fetch-depth: 0 - name: Build Pip package + id: build run: | - # This is needed so that the Git tag is parsed and the version is retrieved + # This is needed so that the Git tag is parsed and the version is + # retrieved git config --global --add safe.directory $(realpath .) # Upgrade Pip @@ -48,6 +52,10 @@ jobs: # Build the source package (sdist) only python -m build --sdist + + # Get built package version and make it accessible to subsequent jobs + PACKAGE_VERSION=$(python -m build --metadata | jq ".version" | tr -d '"') + echo "PACKAGE_VERSION=$PACKAGE_VERSION" >> "$GITHUB_OUTPUT" - name: Upload the package as artifact uses: actions/upload-artifact@v4 with: @@ -83,6 +91,7 @@ jobs: apt-get install -y python3 python3-pip python3-venv elif command -v dnf; then dnf install -y python3 python3-pip + # Install findutils on Rocky Linux when xargs cannot be found if ! command -v xargs; then dnf install -y findutils @@ -99,12 +108,14 @@ jobs: VENV_ACTIVATE_SCRIPT="khiops-venv/bin/activate" fi echo "VENV_ACTIVATE_SCRIPT=$VENV_ACTIVATE_SCRIPT" >> "$GITHUB_ENV" + # Setup Python (be portable wrt. python vs python3 in runners and # containers; either python3 or python is present as per the Python # installation step in the Docker container contexts) PYTHON=$(basename $(command -v python3 || command -v python)) echo "PYTHON=$PYTHON" >> "$GITHUB_ENV" - - name: Checkout sources # Checkout the sources to be able to extract the dependencies list + # Checkout the sources to be able to extract the dependencies list + - name: Checkout sources uses: actions/checkout@v4 with: # Get Git tags @@ -130,30 +141,36 @@ jobs: chown -R $(whoami) /github/home/.cache/pip fi - # Install the Khiops Python library - # Use a virtualenv if required if [[ "${{ matrix.env.use-virtualenv }}" == "true" ]]; then $PYTHON -m venv khiops-venv source "$VENV_ACTIVATE_SCRIPT" fi $PYTHON -m pip install --upgrade pip + # Add homogeneous TOML support (Python >= 3.12 has standard tomllib) $PYTHON -c "import tomllib" 2>/dev/null || $PYTHON -m pip install tomli - # First, install all dependencies except khiops-core and khiops-drivers-* + + # Install all dependencies except khiops-* $PYTHON scripts/extract_dependencies_from_pyproject_toml.py -f "pyproject.toml" --exclude-khiops-family > requires-no-khiops.txt [ ! -s requires-no-khiops.txt ] || xargs $PYTHON -m pip install < requires-no-khiops.txt + # On Windows, the `impi-rt` MPI dependency must be installed # separately, from PyPI, because it is not present on TestPyPI if [[ $RUNNER_OS == 'Windows' ]]; then $PYTHON -m pip install impi-rt fi - # khiops-core and khiops-drivers-* must always be installed from TestPyPI in order to avoid distorting usage statistics + + # khiops-core and khiops-drivers-* must always be installed from + # TestPyPI in order to avoid distorting usage statistics $PYTHON scripts/extract_dependencies_from_pyproject_toml.py -f "pyproject.toml" --khiops-family-only > requires-khiops.txt [ ! -s requires-khiops.txt ] || xargs $PYTHON -m pip install --index-url https://test.pypi.org/simple < requires-khiops.txt rm -f requires-khiops.txt requires-no-khiops.txt - # Lastly, install khiops-python + + # Install the khiops package $PYTHON -m pip install khiops*.tar.gz + + # Deactivate virtualenv if used if [[ "${{ matrix.env.use-virtualenv }}" == "true" ]]; then deactivate fi @@ -198,41 +215,42 @@ jobs: # The MPI command is not always named mpiexec, but can be orterun etc # (as given by khiops_env) kh-status | grep "MPI command" | grep -vwq "" + + # Deactivate virtualenv if used if [[ "${{ matrix.env.use-virtualenv }}" == "true" ]]; then deactivate fi + check-package-version: + if: github.ref_type == 'tag' + needs: build + runs-on: ubuntu-24.04 + steps: - name: Test package / Git tag version coherence + env: + PACKAGE_VERSION: ${{ needs.build.outputs.package-version }} shell: bash - if: github.ref_type == 'tag' run: | # Don't exit on first error: print relevant error message set +e - # Use a virtualenv if required - if [[ "${{ matrix.env.use-virtualenv }}" == "true" ]]; then - source "$VENV_ACTIVATE_SCRIPT" - fi + # Convert pre-release version specification in the Git tag to the Pip # format and check that it matches the Pip package version - PACKAGE_VERSION=$($PYTHON -m pip show khiops | awk 'BEGIN {FS = ": "} $1 ~ /^Version$/ {print $2}') - if [[ "${{ matrix.env.use-virtualenv }}" == "true" ]]; then - deactivate - fi - # Remove any '.' or '-' from the versions to be able to compare them canonically - canonic_tag_name=$(echo "${{ github.ref_name }}" | perl -pe "s/[\.-]//g") - canonic_package_version=$(echo $PACKAGE_VERSION | perl -pe "s/[\.-]//g") - if [[ "$canonic_tag_name" != "$canonic_package_version" ]] + echo "${{ github.ref_name }}" | tr -d '-' | rev | sed -E 's/\.([^0-9].*)/\1/' | rev | \ + grep -wq "$PACKAGE_VERSION" + if [[ $? -ne 0 ]] then echo "::error::Python package version $PACKAGE_VERSION does not match Git tag ${{ github.ref_name }}" false fi + # The implementation of a unique release job with multiple conditional steps # for each publishing mode is not chosen # because of the required job environment verified for Trusted Publishing release-github: # only publish on tag pushes if: github.ref_type == 'tag' && github.repository_owner == 'KhiopsML' - needs: [build, test] - runs-on: ubuntu-22.04 + needs: [test, check-package-version] + runs-on: ubuntu-24.04 permissions: contents: write steps: @@ -253,8 +271,8 @@ jobs: release-testpypi: # only publish on testpypi if requested and on tag pushes if: inputs.pypi-target == 'testpypi' && github.ref_type == 'tag' && github.repository_owner == 'KhiopsML' - needs: [build, test] - runs-on: ubuntu-22.04 + needs: [test, check-package-version] + runs-on: ubuntu-24.04 permissions: # IMPORTANT: OIDC token mandatory for trusted publishing on TestPyPI and PyPI id-token: write @@ -275,8 +293,8 @@ jobs: release-pypi: # only publish on pypi if requested and on tag pushes if: inputs.pypi-target == 'pypi' && github.ref_type == 'tag' && github.repository_owner == 'KhiopsML' - needs: [build, test] - runs-on: ubuntu-22.04 + needs: [test, check-package-version] + runs-on: ubuntu-24.04 permissions: # IMPORTANT: OIDC token mandatory for trusted publishing on TestPyPI and PyPI id-token: write