Skip to content

chore(deps): Bump cython from 3.2.5 to 3.2.8 in /tests #1449

chore(deps): Bump cython from 3.2.5 to 3.2.8 in /tests

chore(deps): Bump cython from 3.2.5 to 3.2.8 in /tests #1449

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 });
}