Repository: probabl-ai/skore
Pull request #1666: ci: Factorize `skore*.yml` in `pytest.yml`
Author: login: thomass-dev
Created: 2025-05-07T14:44:37Z | Merged: 2025-05-26T09:58:19Z

Factorize `skore*.yml` workflows in `pytest.yml`  to run jobs on all packages defined by `vars.PACKAGES`, managed in the GitHub interface.


Diff:
diff --git a/.github/workflows/pr-display-code-coverage.yml b/.github/workflows/pr-display-code-coverage.yml
index 2dc22e4e3f..b8b1bf67e4 100644
--- a/.github/workflows/pr-display-code-coverage.yml
+++ b/.github/workflows/pr-display-code-coverage.yml
@@ -2,19 +2,23 @@ name: pr-display-code-coverage
 
 on:
   workflow_run:
-    workflows: [skore, skore-hub-project, skore-local-project]
+    workflows: [pytest]
     types: [completed]
 
 concurrency:
-  group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event.workflow_run.name }}
+  group: ${{ github.workflow }}-${{ github.ref }}
   cancel-in-progress: true
 
 permissions: {}
 
 jobs:
   pr-display-code-coverage:
-    if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }}
     runs-on: ubuntu-latest
+    if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }}
+    strategy:
+      fail-fast: false
+      matrix:
+        package: ${{ fromJSON(vars.PACKAGES) }}
     permissions:
       actions: read
       contents: read
@@ -30,18 +34,21 @@ jobs:
         uses: ./.github/actions/workflow-run/context
 
       - name: Download coverage reports
+        id: download-coverage-reports
+        continue-on-error: True
         uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
         with:
-          name: ${{ github.event.workflow_run.name }}-coverage
+          name: ${{ matrix.package }}-coverage
           path: coverage/
           github-token: ${{ github.token }}
           run-id: ${{ github.event.workflow_run.id }}
 
       - name: Display coverage reports
+        if: ${{ steps.download-coverage-reports.outcome == 'success' }}
         uses: MishaKav/pytest-coverage-comment@13d3c18e21895566c746187c9ea74736372e5e91 # v1.1.54
         with:
           issue-number: ${{ steps.acquire-pr-context.outputs.pr-number }}
           pytest-xml-coverage-path: coverage/pytest-coverage.xml
           junitxml-path: coverage/pytest.xml
-          title: Coverage Report for `${{ github.event.workflow_run.name }}/`
-          unique-id-for-comment: ${{ github.event.workflow_run.name }}
+          title: Coverage Report for `${{ matrix.package }}/`
+          unique-id-for-comment: ${{ matrix.package }}
diff --git a/.github/workflows/skore-local-project.yml b/.github/workflows/pytest.yml
similarity index 53%
rename from .github/workflows/skore-local-project.yml
rename to .github/workflows/pytest.yml
index 31eb2b86a6..8f05ac37c3 100644
--- a/.github/workflows/skore-local-project.yml
+++ b/.github/workflows/pytest.yml
@@ -1,4 +1,24 @@
-name: skore-local-project
+name: pytest
+
+# **How it works**
+# ================
+#
+# The workflow runs `pytest` jobs on all the repository packages, identified by the JSON
+# list `vars.PACKAGES` managed in the GitHub interface. If you want to run this workflow
+# on a new package, you only have to add its name in the above list.
+#
+# It's important to notice that only one workflow is triggered for all packages.
+#
+# The workflow is triggered on:
+# - __pull_request__ or __merge_group__ event (A),
+# - __push__ event on the main branch (B).
+#
+# On (A), the workflow is started and runs jobs on modified packages, and only on modified
+# packages.
+#
+# On (B), the workflow is started and runs jobs on all packages, no matter if they have
+# modification. Indeed it's important to know on main, at each commit, if all workflows
+# are green.
 
 on:
   pull_request:
@@ -16,33 +36,45 @@ permissions: {}
 
 defaults:
   run:
-    shell: "bash"
+    shell: bash
 
 jobs:
-  skore-local-project-changes:
+  pytest-changes:
     runs-on: ubuntu-latest
     outputs:
-      changes: ${{ steps.filter.outputs.skore-local-project }}
+      modified-packages: ${{ steps.filter.outputs.changes }}
     permissions:
       pull-requests: read
     steps:
       - name: Checkout code
         uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
 
+      - name: Create dynamically filtering file, based on `vars.PACKAGES`
+        run: |
+            echo "${PACKAGES}" | jq -r '.[]' | while read package; do
+                >>${FILEPATH} echo "${package}:
+                - '.github/workflows/pytest.yml'
+                - 'ci/requirements/${package}/**'
+                - '${package}/**'"
+            done
+        env:
+          PACKAGES: ${{ vars.PACKAGES }}
+          FILEPATH: ${{ runner.temp }}/filters.yaml
+
       - name: Define if at least one file has changed
-        uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
         id: filter
+        uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
         with:
-          filters: |
-            skore-local-project:
-              - '.github/workflows/skore-local-project.yml'
-              - 'ci/requirements/skore-local-project/**'
-              - 'skore-local-project/**'
-
-  skore-local-project-lockfiles:
-    runs-on: "ubuntu-latest"
-    needs: [skore-local-project-changes]
-    if: ${{ (contains(fromJSON('["pull_request", "merge_group"]'), github.event_name)) && (needs.skore-local-project-changes.outputs.changes == 'true') }}
+          filters: ${{ runner.temp }}/filters.yaml
+
+  pytest-lockfiles:
+    runs-on: ubuntu-latest
+    needs: [pytest-changes]
+    if: ${{ (contains(fromJSON('["pull_request", "merge_group"]'), github.event_name)) && (needs.pytest-changes.outputs.modified-packages != '[]') }}
+    strategy:
+      fail-fast: false
+      matrix:
+        package: ${{ fromJSON(needs.pytest-changes.outputs.modified-packages) }}
     permissions:
       contents: read
     steps:
@@ -72,34 +104,46 @@ jobs:
           changes=$(git diff --name-only HEAD^1 HEAD)
 
           if
-            (echo "${changes}" | grep -qE "skore-local-project/pyproject.toml") &&
-            (echo "${changes}" | (! grep -qE "ci/requirements/skore-local-project/.*/test-requirements.txt"))
+            (echo "${changes}" | grep -qE "${{ matrix.package }}/pyproject.toml") &&
+            (echo "${changes}" | (! grep -qE "ci/requirements/${{ matrix.package }}/.*/test-requirements.txt"))
           then
               curl -LsSf https://astral.sh/uv/0.6.16/install.sh | sh
-              bash ci/pip-compile.sh skore-local-project
+              bash ci/pip-compile.sh ${{ matrix.package }}
 
-              if (git diff --name-only | grep -qE "ci/requirements/skore-local-project/.*/test-requirements.txt"); then
-                  echo '::error title=skore-local-project-lockfiles::Lockfiles obsolete, please execute `$ bash ci/pip-compile.sh skore-local-project`'
+              if (git diff --name-only | grep -qE "ci/requirements/${{ matrix.package }}/.*/test-requirements.txt"); then
+                  echo '::error title=${{ matrix.package }}-lockfiles::Lockfiles obsolete, please execute `$ bash ci/pip-compile.sh ${{ matrix.package }}`'
                   exit 1
              fi
           fi
 
-  skore-local-project-test:
-    needs: [skore-local-project-changes]
-    if: ${{ (github.event_name == 'push') || (needs.skore-local-project-changes.outputs.changes == 'true') }}
+  pytest-test:
+    needs: [pytest-changes]
+    if: ${{ (github.event_name == 'push') || (needs.pytest-changes.outputs.modified-packages != '[]') }}
     strategy:
       fail-fast: false
       matrix:
+        package: ${{ (github.event_name == 'push') && fromJSON(vars.PACKAGES) || fromJSON(needs.pytest-changes.outputs.modified-packages) }}
         os: ["ubuntu-latest", "windows-latest"]
         python: ["3.9", "3.10", "3.11", "3.12"]
-        scikit-learn: ["1.6"]
-        include:
-          - os: "ubuntu-latest"
-            python: "3.12"
+        scikit-learn: ["1.4", "1.5", "1.6"]
+        exclude:
+          - python: "3.9"
             scikit-learn: "1.4"
-          - os: "ubuntu-latest"
-            python: "3.12"
+          - python: "3.10"
+            scikit-learn: "1.4"
+          - python: "3.11"
+            scikit-learn: "1.4"
+          - os: "windows-latest"
+            scikit-learn: "1.4"
+          - python: "3.9"
+            scikit-learn: "1.5"
+          - python: "3.10"
             scikit-learn: "1.5"
+          - python: "3.11"
+            scikit-learn: "1.5"
+          - os: "windows-latest"
+            scikit-learn: "1.5"
+        include:
           - os: "ubuntu-latest"
             python: "3.12"
             scikit-learn: "1.6"
@@ -123,15 +167,15 @@ jobs:
         uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
         id: cache-python-venv
         with:
-          path: 'skore-local-project/venv'
+          path: ${{ matrix.package }}/venv
           key: >-
             python-venv
             -${{ matrix.os }}
             -${{ steps.setup-python.outputs.python-version }}
-            -${{ hashFiles(format('ci/requirements/skore-local-project/python-{0}/scikit-learn-{1}/test-requirements.txt', matrix.python, matrix.scikit-learn)) }}
+            -${{ hashFiles(format('ci/requirements/{0}/python-{1}/scikit-learn-{2}/test-requirements.txt', matrix.package, matrix.python, matrix.scikit-learn)) }}
 
       - name: Setup python-venv
-        working-directory: "skore-local-project/"
+        working-directory: ${{ matrix.package }}/
         run: |
           set -eu
 
@@ -140,15 +184,15 @@ jobs:
 
           # Activate venv for each step depending on the OS
           if [[ "${{ matrix.os }}" == "ubuntu-latest" ]]; then
-              echo "${GITHUB_WORKSPACE}/skore-local-project/venv/bin" >> ${GITHUB_PATH}
-              echo "VIRTUAL_ENV=${GITHUB_WORKSPACE}/skore-local-project/venv" >> ${GITHUB_ENV}
+              echo "${GITHUB_WORKSPACE}/${{ matrix.package }}/venv/bin" >> ${GITHUB_PATH}
+              echo "VIRTUAL_ENV=${GITHUB_WORKSPACE}/${{ matrix.package }}/venv" >> ${GITHUB_ENV}
           else
-              echo "${GITHUB_WORKSPACE}\\skore-local-project\\venv\\Scripts" >> ${GITHUB_PATH}
-              echo "VIRTUAL_ENV=${GITHUB_WORKSPACE}\\skore-local-project\\venv" >> ${GITHUB_ENV}
+              echo "${GITHUB_WORKSPACE}\\${{ matrix.package }}\\venv\\Scripts" >> ${GITHUB_PATH}
+              echo "VIRTUAL_ENV=${GITHUB_WORKSPACE}\\${{ matrix.package }}\\venv" >> ${GITHUB_ENV}
           fi
 
       - name: Install dependencies in python-venv
-        working-directory: ${{ format('ci/requirements/skore-local-project/python-{0}/scikit-learn-{1}', matrix.python, matrix.scikit-learn) }}
+        working-directory: ${{ format('ci/requirements/{0}/python-{1}/scikit-learn-{2}', matrix.package, matrix.python, matrix.scikit-learn) }}
         if: steps.cache-python-venv.outputs.cache-hit != 'true'
         run: |
           python -m pip install --upgrade pip build
@@ -158,27 +202,27 @@ jobs:
         uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
         if: steps.cache-python-venv.outputs.cache-hit != 'true'
         with:
-          path: 'skore-local-project/venv'
+          path: ${{ matrix.package }}/venv
           key: ${{ steps.cache-python-venv.outputs.cache-primary-key }}
 
       - name: Build
-        working-directory: skore-local-project/
+        working-directory: ${{ matrix.package }}/
         run: python -m build
 
       - name: Install
-        working-directory: skore-local-project/dist/
+        working-directory: ${{ matrix.package }}/dist/
         run: wheel=(*.whl); python -m pip install --force-reinstall --no-deps "${wheel}"
 
       - name: Test without coverage
         if: ${{ ! matrix.coverage }}
         timeout-minutes: 10
-        working-directory: skore-local-project/
+        working-directory: ${{ matrix.package }}/
         run: python -m pytest -n auto src/ tests/ --no-cov
 
       - name: Test with coverage
         if: ${{ matrix.coverage }}
         timeout-minutes: 10
-        working-directory: skore-local-project/
+        working-directory: ${{ matrix.package }}/
         run: |
           mkdir coverage
           python -m pytest -n auto src/ tests/ --junitxml=coverage/pytest.xml --cov-config=pyproject.toml --cov-report=xml:coverage/pytest-coverage.xml --cov
@@ -187,17 +231,16 @@ jobs:
         if: ${{ matrix.coverage && (github.event_name == 'pull_request') }}
         uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
         with:
-          name: skore-local-project-coverage
-          path: skore-local-project/coverage/
+          name: ${{ matrix.package }}-coverage
+          path: ${{ matrix.package }}/coverage/
 
-  skore-local-project:
+  pytest:
     needs:
-      - skore-local-project-changes
-      - skore-local-project-lockfiles
-      - skore-local-project-test
+      - pytest-changes
+      - pytest-lockfiles
+      - pytest-test
     if: ${{ always() }}
-    runs-on: Ubuntu-latest
+    runs-on: ubuntu-latest
     steps:
-      - shell: bash
-        run: |
+      - run: |
           [[  ${{ contains(needs.*.result, 'failure') }} = false ]]
diff --git a/.github/workflows/skore-hub-project.yml b/.github/workflows/skore-hub-project.yml
deleted file mode 100644
index adc29deda9..0000000000
--- a/.github/workflows/skore-hub-project.yml
+++ /dev/null
@@ -1,203 +0,0 @@
-name: skore-hub-project
-
-on:
-  pull_request:
-  push:
-    branches:
-      - main
-  merge_group:
-    types: [checks_requested]
-
-concurrency:
-  group: ${{ github.workflow }}-${{ github.ref }}
-  cancel-in-progress: true
-
-permissions: {}
-
-defaults:
-  run:
-    shell: "bash"
-
-jobs:
-  skore-hub-project-changes:
-    runs-on: ubuntu-latest
-    outputs:
-      changes: ${{ steps.filter.outputs.skore-hub-project }}
-    permissions:
-      pull-requests: read
-    steps:
-      - name: Checkout code
-        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-
-      - name: Define if at least one file has changed
-        uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
-        id: filter
-        with:
-          filters: |
-            skore-hub-project:
-              - '.github/workflows/skore-hub-project.yml'
-              - 'ci/requirements/skore-hub-project/**'
-              - 'skore-hub-project/**'
-
-  skore-hub-project-lockfiles:
-    runs-on: "ubuntu-latest"
-    needs: [skore-hub-project-changes]
-    if: ${{ (contains(fromJSON('["pull_request", "merge_group"]'), github.event_name)) && (needs.skore-hub-project-changes.outputs.changes == 'true') }}
-    permissions:
-      contents: read
-    steps:
-      - name: Checkout code
-        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-        with:
-          fetch-depth: 2
-
-      - name: Check lockfiles are not obsolete
-        run: |
-          set -eu
-
-          # Check if `pyproject.toml` has changed in this pull-request
-          # ├── False
-          # │   └── Exit 0
-          # └── True
-          #     └── Check if lockfiles have changed in this pull-request
-          #         ├── True
-          #         │   └── Exit 0
-          #         └── False
-          #             └── Recompile lockfiles and check if they have to change
-          #                 ├── False
-          #                 │   └── Exit 0
-          #                 └── True
-          #                     └── Exit 1
-
-          changes=$(git diff --name-only HEAD^1 HEAD)
-
-          if
-            (echo "${changes}" | grep -qE "skore-hub-project/pyproject.toml") &&
-            (echo "${changes}" | (! grep -qE "ci/requirements/skore-hub-project/.*/test-requirements.txt"))
-          then
-              curl -LsSf https://astral.sh/uv/0.6.16/install.sh | sh
-              bash ci/pip-compile.sh skore-hub-project
-
-              if (git diff --name-only | grep -qE "ci/requirements/skore-hub-project/.*/test-requirements.txt"); then
-                  echo '::error title=skore-hub-project-lockfiles::Lockfiles obsolete, please execute `$ bash ci/pip-compile.sh skore-hub-project`'
-                  exit 1
-             fi
-          fi
-
-  skore-hub-project-test:
-    needs: [skore-hub-project-changes]
-    if: ${{ (github.event_name == 'push') || (needs.skore-hub-project-changes.outputs.changes == 'true') }}
-    strategy:
-      fail-fast: false
-      matrix:
-        os: ["ubuntu-latest", "windows-latest"]
-        python: ["3.9", "3.10", "3.11", "3.12"]
-        scikit-learn: ["1.6"]
-        include:
-          - os: "ubuntu-latest"
-            python: "3.12"
-            scikit-learn: "1.4"
-          - os: "ubuntu-latest"
-            python: "3.12"
-            scikit-learn: "1.5"
-          - os: "ubuntu-latest"
-            python: "3.12"
-            scikit-learn: "1.6"
-            coverage: true
-    runs-on: ${{ matrix.os }}
-    permissions:
-      contents: read
-    steps:
-      - name: Checkout code
-        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-
-      - name: Setup Python
-        uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
-        id: setup-python
-        with:
-          python-version: ${{ matrix.python }}
-          check-latest: True
-          cache: pip
-
-      - name: Restore python-venv
-        uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
-        id: cache-python-venv
-        with:
-          path: 'skore-hub-project/venv'
-          key: >-
-            python-venv
-            -${{ matrix.os }}
-            -${{ steps.setup-python.outputs.python-version }}
-            -${{ hashFiles(format('ci/requirements/skore-hub-project/python-{0}/scikit-learn-{1}/test-requirements.txt', matrix.python, matrix.scikit-learn)) }}
-
-      - name: Setup python-venv
-        working-directory: "skore-hub-project/"
-        run: |
-          set -eu
-
-          # Ensure venv is created
-          python -m venv venv
-
-          # Activate venv for each step depending on the OS
-          if [[ "${{ matrix.os }}" == "ubuntu-latest" ]]; then
-              echo "${GITHUB_WORKSPACE}/skore-hub-project/venv/bin" >> ${GITHUB_PATH}
-              echo "VIRTUAL_ENV=${GITHUB_WORKSPACE}/skore-hub-project/venv" >> ${GITHUB_ENV}
-          else
-              echo "${GITHUB_WORKSPACE}\\skore-hub-project\\venv\\Scripts" >> ${GITHUB_PATH}
-              echo "VIRTUAL_ENV=${GITHUB_WORKSPACE}\\skore-hub-project\\venv" >> ${GITHUB_ENV}
-          fi
-
-      - name: Install dependencies in python-venv
-        working-directory: ${{ format('ci/requirements/skore-hub-project/python-{0}/scikit-learn-{1}', matrix.python, matrix.scikit-learn) }}
-        if: steps.cache-python-venv.outputs.cache-hit != 'true'
-        run: |
-          python -m pip install --upgrade pip build
-          python -m pip install --requirement test-requirements.txt
-
-      - name: Save python-venv
-        uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
-        if: steps.cache-python-venv.outputs.cache-hit != 'true'
-        with:
-          path: 'skore-hub-project/venv'
-          key: ${{ steps.cache-python-venv.outputs.cache-primary-key }}
-
-      - name: Build
-        working-directory: skore-hub-project/
-        run: python -m build
-
-      - name: Install
-        working-directory: skore-hub-project/dist/
-        run: wheel=(*.whl); python -m pip install --force-reinstall --no-deps "${wheel}"
-
-      - name: Test without coverage
-        if: ${{ ! matrix.coverage }}
-        timeout-minutes: 10
-        working-directory: skore-hub-project/
-        run: python -m pytest -n auto src/ tests/ --no-cov
-
-      - name: Test with coverage
-        if: ${{ matrix.coverage }}
-        timeout-minutes: 10
-        working-directory: skore-hub-project/
-        run: |
-          mkdir coverage
-          python -m pytest -n auto src/ tests/ --junitxml=coverage/pytest.xml --cov-config=pyproject.toml --cov-report=xml:coverage/pytest-coverage.xml --cov
-
-      - name: Upload coverage reports
-        if: ${{ matrix.coverage && (github.event_name == 'pull_request') }}
-        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
-        with:
-          name: skore-hub-project-coverage
-          path: skore-hub-project/coverage/
-
-  skore-hub-project:
-    needs:
-      - skore-hub-project-changes
-      - skore-hub-project-lockfiles
-      - skore-hub-project-test
-    if: ${{ always() }}
-    runs-on: Ubuntu-latest
-    steps:
-      - shell: bash
-        run: |
-          [[  ${{ contains(needs.*.result, 'failure') }} = false ]]
diff --git a/.github/workflows/skore.yml b/.github/workflows/skore.yml
deleted file mode 100644
index 4612c1c6e1..0000000000
--- a/.github/workflows/skore.yml
+++ /dev/null
@@ -1,207 +0,0 @@
-name: skore
-
-on:
-  pull_request:
-  push:
-    branches:
-      - main
-  merge_group:
-    types: [checks_requested]
-
-concurrency:
-  group: ${{ github.workflow }}-${{ github.ref }}
-  cancel-in-progress: true
-
-permissions: {}
-
-defaults:
-  run:
-    shell: "bash"
-
-jobs:
-  skore-changes:
-    runs-on: ubuntu-latest
-    outputs:
-      changes: ${{ steps.filter.outputs.skore }}
-    permissions:
-      pull-requests: read
-    steps:
-      - name: Checkout code
-        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-
-      - name: Define if at least one file has changed
-        uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
-        id: filter
-        with:
-          filters: |
-            skore:
-              - '.github/workflows/skore.yml'
-              - 'ci/requirements/skore/**'
-              - 'skore/**'
-
-  skore-lockfiles:
-    runs-on: "ubuntu-latest"
-    needs: [skore-changes]
-    if: ${{ (contains(fromJSON('["pull_request", "merge_group"]'), github.event_name)) && (needs.skore-changes.outputs.changes == 'true') }}
-    permissions:
-      contents: read
-    steps:
-      - name: Checkout code
-        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-        with:
-          fetch-depth: 2
-
-      - name: Check lockfiles are not obsolete
-        run: |
-          set -eu
-
-          # Check if `pyproject.toml` has changed in this pull-request
-          # ├── False
-          # │   └── Exit 0
-          # └── True
-          #     └── Check if lockfiles have changed in this pull-request
-          #         ├── True
-          #         │   └── Exit 0
-          #         └── False
-          #             └── Recompile lockfiles and check if they have to change
-          #                 ├── False
-          #                 │   └── Exit 0
-          #                 └── True
-          #                     └── Exit 1
-
-          changes=$(git diff --name-only HEAD^1 HEAD)
-
-          if
-            (echo "${changes}" | grep -qE "skore/pyproject.toml") &&
-            (echo "${changes}" | (! grep -qE "ci/requirements/skore/.*/test-requirements.txt"))
-          then
-              curl -LsSf https://astral.sh/uv/0.6.16/install.sh | sh
-              bash ci/pip-compile.sh skore
-
-              if (git diff --name-only | grep -qE "ci/requirements/skore/.*/test-requirements.txt"); then
-                  echo '::error title=skore-lockfiles::Lockfiles obsolete, please execute `$ bash ci/pip-compile.sh skore`'
-                  exit 1
-             fi
-          fi
-
-  skore-test:
-    needs: [skore-changes]
-    if: ${{ (github.event_name == 'push') || (needs.skore-changes.outputs.changes == 'true') }}
-    strategy:
-      fail-fast: false
-      matrix:
-        os: ["ubuntu-latest", "windows-latest"]
-        python: ["3.9", "3.10", "3.11", "3.12"]
-        scikit-learn: ["1.6"]
-        include:
-          - os: "ubuntu-latest"
-            python: "3.12"
-            scikit-learn: "1.4"
-          - os: "ubuntu-latest"
-            python: "3.12"
-            scikit-learn: "1.5"
-          - os: "ubuntu-latest"
-            python: "3.12"
-            scikit-learn: "1.6"
-            coverage: true
-    runs-on: ${{ matrix.os }}
-    permissions:
-      contents: read
-    steps:
-      - name: Checkout code
-        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-
-      - name: Setup Python
-        uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
-        id: setup-python
-        with:
-          python-version: ${{ matrix.python }}
-          check-latest: True
-          cache: pip
-
-      - name: Restore python-venv
-        uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
-        id: cache-python-venv
-        with:
-          path: 'skore/venv'
-          key: >-
-            python-venv
-            -${{ matrix.os }}
-            -${{ steps.setup-python.outputs.python-version }}
-            -${{ hashFiles(format('ci/requirements/skore/python-{0}/scikit-learn-{1}/test-requirements.txt', matrix.python, matrix.scikit-learn)) }}
-
-      - name: Setup python-venv
-        working-directory: "skore/"
-        run: |
-          set -eu
-
-          # Ensure venv is created
-          python -m venv venv
-
-          # Activate venv for each step depending on the OS
-          if [[ "${{ matrix.os }}" == "ubuntu-latest" ]]; then
-              echo "${GITHUB_WORKSPACE}/skore/venv/bin" >> ${GITHUB_PATH}
-              echo "VIRTUAL_ENV=${GITHUB_WORKSPACE}/skore/venv" >> ${GITHUB_ENV}
-          else
-              echo "${GITHUB_WORKSPACE}\\skore\\venv\\Scripts" >> ${GITHUB_PATH}
-              echo "VIRTUAL_ENV=${GITHUB_WORKSPACE}\\skore\\venv" >> ${GITHUB_ENV}
-          fi
-
-      - name: Install dependencies in python-venv
-        working-directory: ${{ format('ci/requirements/skore/python-{0}/scikit-learn-{1}', matrix.python, matrix.scikit-learn) }}
-        if: steps.cache-python-venv.outputs.cache-hit != 'true'
-        run: |
-          python -m pip install --upgrade pip build
-          python -m pip install --requirement test-requirements.txt
-
-      - name: Save python-venv
-        uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
-        if: steps.cache-python-venv.outputs.cache-hit != 'true'
-        with:
-          path: 'skore/venv'
-          key: ${{ steps.cache-python-venv.outputs.cache-primary-key }}
-
-      - name: Build
-        working-directory: skore/
-        run: python -m build
-
-      - name: Install
-        working-directory: skore/dist/
-        run: wheel=(*.whl); python -m pip install --force-reinstall --no-deps "${wheel}"
-
-      - name: Show dependencies versions
-        working-directory: skore/
-        run: python -c 'import skore; skore.show_versions()'
-
-      - name: Test without coverage
-        if: ${{ ! matrix.coverage }}
-        timeout-minutes: 10
-        working-directory: skore/
-        run: python -m pytest -n auto src/ tests/ --no-cov
-
-      - name: Test with coverage
-        if: ${{ matrix.coverage }}
-        timeout-minutes: 10
-        working-directory: skore/
-        run: |
-          mkdir coverage
-          python -m pytest -n auto src/ tests/ --junitxml=coverage/pytest.xml --cov-config=pyproject.toml --cov-report=xml:coverage/pytest-coverage.xml --cov
-
-      - name: Upload coverage reports
-        if: ${{ matrix.coverage && (github.event_name == 'pull_request') }}
-        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
-        with:
-          name: skore-coverage
-          path: skore/coverage/
-
-  skore:
-    needs:
-      - skore-changes
-      - skore-lockfiles
-      - skore-test
-    if: ${{ always() }}
-    runs-on: Ubuntu-latest
-    steps:
-      - shell: bash
-        run: |
-          [[  ${{ contains(needs.*.result, 'failure') }} = false ]]


Reviews:
user: login: thomass-dev
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-07T21:35:52Z
user: login: thomass-dev
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-22T15:06:50Z
user: login: auguste-probabl
body: looks good!
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-26T09:05:05Z

Review comments:
diff_hunk: @@ -72,28 +93,37 @@ jobs:
           changes=$(git diff --name-only HEAD^1 HEAD)
 
           if
-            (echo "${changes}" | grep -qE "skore-remote-project/pyproject.toml") &&
-            (echo "${changes}" | (! grep -qE "ci/requirements/skore-remote-project/.*/test-requirements.txt"))
+            (echo "${changes}" | grep -qE "${{ matrix.package }}/pyproject.toml") &&
+            (echo "${changes}" | (! grep -qE "ci/requirements/${{ matrix.package }}/.*/test-requirements.txt"))
           then
               curl -LsSf https://astral.sh/uv/0.6.16/install.sh | sh
-              bash ci/pip-compile.sh skore-remote-project
+              bash ci/pip-compile.sh ${{ matrix.package }}
 
-              if (git diff --name-only | grep -qE "ci/requirements/skore-remote-project/.*/test-requirements.txt"); then
-                  echo '::error title=skore-remote-project-lockfiles::Lockfiles obsolete, please execute `$ bash ci/pip-compile.sh skore-remote-project`'
+              if (git diff --name-only | grep -qE "ci/requirements/${{ matrix.package }}/.*/test-requirements.txt"); then
+                  echo '::error title=${{ matrix.package }}-lockfiles::Lockfiles obsolete, please execute `$ bash ci/pip-compile.sh ${{ matrix.package }}`'
                   exit 1
              fi
           fi
 
-  skore-remote-project-test:
-    needs: [skore-remote-project-changes]
-    if: ${{ (github.event_name == 'push') || (needs.skore-remote-project-changes.outputs.changes == 'true') }}
+  pytest-test:
+    needs: [pytest-changes]
+    if: ${{ (github.event_name == 'push') || (needs.pytest-changes.outputs.modified-packages != '[]') }}
     strategy:
       fail-fast: false
       matrix:
+        package: ${{ (github.event_name == 'push') && fromJSON(needs.pytest-changes.outputs.all-packages) || fromJSON(needs.pytest-changes.outputs.modified-packages) }}
         os: ["ubuntu-latest", "windows-latest"]
         python: ["3.9", "3.10", "3.11", "3.12"]
-        scikit-learn: ["1.6"]
         include:
+          - python: "3.9"
+            scikit-learn: "1.6"
+          - python: "3.10"
+            scikit-learn: "1.6"
+          - python: "3.11"
+            scikit-learn: "1.6"
+          - os: "windows-latest"
+            python: "3.12"
+            scikit-learn: "1.6"
           - os: "ubuntu-latest"
             python: "3.12"
             scikit-learn: "1.4"
path: .github/workflows/pytest.yml
user: login: thomass-dev
body: To fix: doesn't work as expected.
created_at: 2025-05-07T21:35:52Z
author_association: COLLABORATOR
diff_hunk: @@ -158,31 +188,27 @@ jobs:
         uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
         if: steps.cache-python-venv.outputs.cache-hit != 'true'
         with:
-          path: 'skore/venv'
+          path: ${{ matrix.package }}/venv
           key: ${{ steps.cache-python-venv.outputs.cache-primary-key }}
 
       - name: Build
-        working-directory: skore/
+        working-directory: ${{ matrix.package }}/
         run: python -m build
 
       - name: Install
-        working-directory: skore/dist/
+        working-directory: ${{ matrix.package }}/dist/
         run: wheel=(*.whl); python -m pip install --force-reinstall --no-deps "${wheel}"
 
-      - name: Show dependencies versions
-        working-directory: skore/
-        run: python -c 'import skore; skore.show_versions()'
path: .github/workflows/pytest.yml
user: login: thomass-dev
body: This is deprecated by the use of the lockfiles.
created_at: 2025-05-22T15:06:50Z
author_association: COLLABORATOR

PR comments:
user: login: thomass-dev
created_at: 2025-05-23T15:17:41Z
body: After approval, i will change the required jobs from `skore`+`skore-hub-project`+`skore-local-project` to `pytest`.
author_association: COLLABORATOR
user: login: thomass-dev
created_at: 2025-05-23T15:29:12Z
body: Ready for review.
author_association: COLLABORATOR