chore(deps): Bump cython from 3.2.5 to 3.2.8 in /tests #1449
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| schedule: | |
| - cron: '45 01 30 * *' | |
| push: | |
| fork: | |
| workflow_dispatch: | |
| workflow_call: | |
| jobs: | |
| detect-changes: | |
| name: Detect env/Dockerfile changes | |
| runs-on: ubuntu-latest | |
| outputs: | |
| images: ${{ steps.filter.outputs.images }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: dorny/paths-filter@v4 | |
| id: filter | |
| with: | |
| filters: | | |
| images: | |
| - 'tests/environment.*.yml' | |
| - 'docker/Dockerfile.nmisp-test' | |
| - '.github/workflows/build-test-image.yml' | |
| build-images: | |
| name: Build test images | |
| needs: detect-changes | |
| if: needs.detect-changes.outputs.images == 'true' | |
| permissions: | |
| contents: read | |
| packages: write | |
| uses: ./.github/workflows/build-test-image.yml | |
| test_utils: | |
| name: Check utils | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: checkout | |
| id: checkout | |
| uses: actions/checkout@v6 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| version: "latest" | |
| enable-cache: true | |
| cache-suffix: "uv" | |
| cache-dependency-glob: "utils/requirements.txt" | |
| - name: Create venv | |
| run: uv venv my_env | |
| - name: setup environment | |
| id: setup | |
| run: | | |
| source my_env/bin/activate | |
| uv pip install -r ./utils/requirements.txt | |
| - name: list packages | |
| id: list_pakcages | |
| run: | | |
| source my_env/bin/activate | |
| uv pip list | |
| - name: check utils | |
| id: check_utils | |
| run: | | |
| source my_env/bin/activate | |
| python -m pytest -n auto ./utils/tests/ | |
| badges: | |
| name: Add Google Colab Badges | |
| needs: test_utils | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| timeout-minutes: 5 | |
| steps: | |
| - name: checkout | |
| id: checkout | |
| uses: actions/checkout@v6 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| version: "latest" | |
| enable-cache: true | |
| cache-suffix: "uv-badges" | |
| cache-dependency-glob: "utils/add_colab_main_buttons.py" | |
| - name: Add/Update badges | |
| id: badges | |
| run: uv run utils/add_colab_main_buttons.py | |
| - name: Commit & push | |
| id: commit | |
| if: github.actor != 'dependabot[bot]' | |
| uses: stefanzweifel/git-auto-commit-action@v7 | |
| with: | |
| commit_message : "Clean ipynb ${{ github.sha }}" | |
| test_ipynb_linux: | |
| needs: [badges, build-images] | |
| if: always() && needs.badges.result == 'success' && (needs.build-images.result == 'success' || needs.build-images.result == 'skipped') | |
| name: ${{ matrix.anaconda }} on linux (container) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: read | |
| container: | |
| image: ghcr.io/${{ github.repository_owner }}/nmisp-test:latest-${{ matrix.anaconda }} | |
| credentials: | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| strategy: | |
| matrix: | |
| anaconda: ["2023.09", "nightly"] | |
| fail-fast: false | |
| timeout-minutes: 30 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: pytest | |
| env: | |
| TEST_IPYNB_IGNORE_FOLDER: tutorial | |
| run: | | |
| python --version | |
| python -m pytest --numprocesses=auto -k 'not (links or update_nmisp_py)' ./tests/ | |
| test_ipynb_native: | |
| needs: badges | |
| name: ${{ matrix.anaconda }} on ${{ matrix.os }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| os: [windows-latest, macOS-latest] | |
| anaconda: ["2023.09", "nightly"] | |
| fail-fast: false | |
| timeout-minutes: 30 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Cache conda packages | |
| uses: actions/cache@v5 | |
| env: | |
| CACHE_NUMBER: 0 | |
| with: | |
| path: ~/conda_pkgs_dir | |
| key: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ hashFiles(format('tests/environment.{0}.yml', matrix.anaconda)) }} | |
| - name: setup conda | |
| uses: conda-incubator/setup-miniconda@v4 | |
| with: | |
| auto-update-conda: true | |
| activate-environment: test-environment | |
| environment-file: ./tests/environment.${{ matrix.anaconda }}.yml | |
| use-only-tar-bz2: true | |
| - name: pytest | |
| env: | |
| TEST_IPYNB_IGNORE_FOLDER: tutorial | |
| run: | | |
| conda env list | |
| conda activate test-environment | |
| conda list | |
| python -m pytest --numprocesses=auto -k 'not (links or update_nmisp_py)' ./tests/ | |
| shell: bash -el {0} | |
| test_ipynb_colab: | |
| needs: badges | |
| name: test ipynb on Google Colab | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: setup python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.12.12' | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| version: "latest" | |
| enable-cache: true | |
| cache-suffix: "uv" | |
| cache-dependency-glob: "tests/requirements.colab.2026.02.txt" | |
| - name: Create venv | |
| run: uv venv my_env | |
| - name: setup environment | |
| id: setup | |
| run: | | |
| source my_env/bin/activate | |
| uv pip install -r ./tests/requirements.colab.2026.02.txt | |
| - name: list packages | |
| id: list_pakcages | |
| run: | | |
| source my_env/bin/activate | |
| uv pip list | |
| - name: pytest | |
| env: | |
| TEST_IPYNB_IGNORE_FOLDER: tutorial | |
| run: | | |
| source my_env/bin/activate | |
| python -m pytest -n auto -k 'not (links or update_nmisp_py)' ./tests | |
| update_nmisp_py: | |
| # Decoupled from test_ipynb_colab: that job is chronically red due to the | |
| # 030 TF+PyTorch dead-kernel notebook, which was silently keeping the | |
| # helper-package sync skipped (issue #440). Still gated behind the native | |
| # notebook test suites so nmisp_py only syncs when real tests pass. | |
| needs: [test_ipynb_linux, test_ipynb_native] | |
| if: github.actor != 'dependabot[bot]' | |
| name: Update nmisp_py | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| timeout-minutes: 5 | |
| steps: | |
| - name: checkout nmisp | |
| uses: actions/checkout@v6 | |
| - name: checkout nmisp_py | |
| uses: actions/checkout@v6 | |
| with: | |
| repository: kwlee2025cpp/nmisp_py | |
| token: ${{ secrets.NMISP_PY_TOKEN }} | |
| path: nmisp_py_dest | |
| - name: setup python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.12' | |
| - name: sync .py files | |
| run: python ./utils/update_nmisp_py.py nmisp_py_dest | |
| - name: commit & push | |
| uses: stefanzweifel/git-auto-commit-action@v7 | |
| with: | |
| commit_message: "Update nmisp_py" | |
| repository: nmisp_py_dest | |
| notify-on-failure: | |
| # Proactive alert so a silent regression can't go unnoticed — e.g. the #440 | |
| # case where update_nmisp_py silently 'skipped' for a long time with no red | |
| # signal. Opens/updates one 'ci-alert' issue when a watched job FAILS, or | |
| # when update_nmisp_py is SKIPPED, and auto-closes it once the watched jobs | |
| # pass. test_ipynb_colab is intentionally NOT watched (chronically red 030 | |
| # dead-kernel) to avoid alerting on every run. | |
| needs: [test_utils, badges, test_ipynb_linux, test_ipynb_native, update_nmisp_py] | |
| if: always() && github.event_name != 'fork' && github.actor != 'dependabot[bot]' | |
| name: Notify on CI failure | |
| runs-on: ubuntu-latest | |
| permissions: | |
| issues: write | |
| steps: | |
| - name: Alert on failed or skipped key jobs | |
| uses: actions/github-script@v7 | |
| env: | |
| NEEDS: ${{ toJSON(needs) }} | |
| with: | |
| script: | | |
| const needs = JSON.parse(process.env.NEEDS); | |
| // Result values that count as a problem, per job. For update_nmisp_py, | |
| // 'skipped' is also bad — that is the silent-staleness signal (#440). | |
| const watch = { | |
| test_utils: ['failure', 'cancelled'], | |
| badges: ['failure', 'cancelled'], | |
| test_ipynb_linux: ['failure', 'cancelled'], | |
| test_ipynb_native: ['failure', 'cancelled'], | |
| update_nmisp_py: ['failure', 'cancelled', 'skipped'], | |
| }; | |
| const bad = Object.keys(watch) | |
| .filter(j => needs[j] && watch[j].includes(needs[j].result)) | |
| .map(j => `${j} → ${needs[j].result}`); | |
| const { owner, repo } = context.repo; | |
| const LABEL = 'ci-alert'; | |
| const runUrl = `${context.serverUrl}/${owner}/${repo}/actions/runs/${context.runId}`; | |
| const sha = context.sha.slice(0, 7); | |
| // ensure the label exists (idempotent) | |
| try { | |
| await github.rest.issues.getLabel({ owner, repo, name: LABEL }); | |
| } catch { | |
| await github.rest.issues.createLabel({ owner, repo, name: LABEL, | |
| color: 'd73a4a', description: 'Automated CI failure / silent-skip alert' }).catch(() => {}); | |
| } | |
| const open = (await github.rest.issues.listForRepo({ | |
| owner, repo, state: 'open', labels: LABEL, per_page: 1 })).data[0]; | |
| if (bad.length === 0) { | |
| if (open) { | |
| await github.rest.issues.createComment({ owner, repo, issue_number: open.number, | |
| body: `✅ Watched jobs green again on \`${context.ref}\` (\`${sha}\`). Auto-closing.\n${runUrl}` }); | |
| await github.rest.issues.update({ owner, repo, issue_number: open.number, state: 'closed' }); | |
| } | |
| return; | |
| } | |
| const body = [ | |
| `🔴 **CI alert** on \`${context.ref}\` (commit \`${sha}\`)`, | |
| '', | |
| 'Problem jobs:', | |
| ...bad.map(b => `- \`${b}\``), | |
| '', | |
| `Run: ${runUrl}`, | |
| '', | |
| '_test_ipynb_colab is not watched (chronically red — 030 dead-kernel). This issue auto-closes when the watched jobs pass._', | |
| ].join('\n'); | |
| if (open) { | |
| await github.rest.issues.createComment({ owner, repo, issue_number: open.number, body }); | |
| } else { | |
| await github.rest.issues.create({ owner, repo, | |
| title: '🔴 CI alert: a key job failed or was skipped', labels: [LABEL], body }); | |
| } |