SciQLop compatibility smoke #12
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: SciQLop compatibility smoke | |
| # Verifies each plugin imports cleanly and that its `load(main_window)` | |
| # entry-point runs against a real SciQLopMainWindow built from a | |
| # configurable SciQLop ref. Catches API-contract breakage before a SciQLop | |
| # release ships — e.g. signature changes on CatalogProvider, removal of an | |
| # attribute plugins relied on, etc. | |
| # | |
| # Default: smokes against SciQLop `main`. Use the workflow_dispatch input | |
| # to point it at a specific pre-release (`0.12.0.dev0`), tagged version, | |
| # or commit SHA. | |
| on: | |
| push: | |
| workflow_dispatch: | |
| inputs: | |
| sciqlop_ref: | |
| description: "SciQLop git ref / PyPI version (e.g. main, 0.12.0.dev0, abcdef1)" | |
| default: main | |
| required: true | |
| schedule: | |
| # weekly against main so regressions surface even without a plugin push | |
| - cron: "0 6 * * 1" | |
| jobs: | |
| smoke: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| plugin: | |
| - { dir: sciqlop_albert, pkg: sciqlop_albert } | |
| - { dir: sciqlop_claude, pkg: sciqlop_claude } | |
| - { dir: sciqlop_copilot, pkg: sciqlop_copilot } | |
| - { dir: sciqlop_msa, pkg: sciqlop_msa } | |
| - { dir: sciqlop_radio, pkg: sciqlop_radio } | |
| - { dir: cdf_workbench, pkg: cdf_workbench } | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.13" | |
| - name: Install OS deps | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y xvfb libatomic1 libglx-dev libegl-dev \ | |
| libxrandr2 libxss1 libxcursor1 libxcomposite1 libasound2-dev \ | |
| libxi6 libxtst6 libglib2.0-bin libdbus-1-3 libxdamage1 \ | |
| libxkbcommon-x11-0 libxcb-cursor0 libxcb-icccm4 libxcb-keysyms1 \ | |
| libxcb-shape0 libnss3 | |
| - name: Install SciQLop @ ${{ github.event.inputs.sciqlop_ref || 'main' }} | |
| run: | | |
| REF="${{ github.event.inputs.sciqlop_ref || 'main' }}" | |
| # Treat anything matching a semver-ish pattern as a PyPI release | |
| # (e.g. "0.12.0", "0.12.0.dev0", "0.11.4"); everything else is a | |
| # git ref against SciQLop/SciQLop. | |
| if [[ "$REF" =~ ^[0-9]+\.[0-9]+\.[0-9]+([a-z0-9.]*)$ ]]; then | |
| pip install "sciqlop==${REF}" | |
| else | |
| pip install "sciqlop @ git+https://github.com/SciQLop/SciQLop@${REF}" | |
| fi | |
| pip install pytest # some plugins import pytest at top level via tests | |
| - name: Install plugin ${{ matrix.plugin.dir }} | |
| run: pip install ./${{ matrix.plugin.dir }} | |
| - name: Install plugin runtime deps from plugin.json | |
| run: | | |
| python - <<'PY' | |
| import json, subprocess, sys, pathlib | |
| mf = pathlib.Path("${{ matrix.plugin.dir }}/${{ matrix.plugin.pkg }}/plugin.json") | |
| if not mf.exists(): | |
| print(f"no plugin.json at {mf} — nothing to install") | |
| sys.exit(0) | |
| deps = json.loads(mf.read_text()).get("python_dependencies", []) | |
| if not deps: | |
| print("plugin.json declares no python_dependencies") | |
| sys.exit(0) | |
| print("Installing:", deps) | |
| subprocess.check_call([sys.executable, "-m", "pip", "install", *deps]) | |
| PY | |
| - name: Smoke — import and load(main_window) | |
| env: | |
| # SciQLop's MainWindow embeds a QWebEngineView; under xvfb | |
| # Chromium needs these flags or it segfaults at startup. Same | |
| # flags SciQLop's own CI uses (.github/workflows/tests.yml). | |
| QT_QPA_PLATFORM: xcb | |
| QTWEBENGINE_DISABLE_SANDBOX: "1" | |
| QTWEBENGINE_CHROMIUM_FLAGS: "--disable-gpu --no-sandbox --disable-software-rasterizer --disable-dev-shm-usage" | |
| INSIDE_SCIQLOP: "1" | |
| SPEASY_SKIP_INIT_PROVIDERS: "1" | |
| run: | | |
| mkdir -p test-config test-data test-workspace test-cache | |
| export XDG_CONFIG_HOME="$PWD/test-config" | |
| export XDG_DATA_HOME="$PWD/test-data" | |
| export XDG_CACHE_HOME="$PWD/test-cache" | |
| export SCIQLOP_WORKSPACE_DIR="$PWD/test-workspace" | |
| xvfb-run -a --server-args="-screen 0 1280x1024x24" python - <<'PY' | |
| import sys, importlib | |
| from PySide6 import QtCore | |
| QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_UseDesktopOpenGL, True) | |
| QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts, True) | |
| from SciQLop.core.sciqlop_application import SciQLopApp | |
| app = SciQLopApp(sys.argv) | |
| # Pre-warm tscat to dodge the same thread race SciQLop's own conftest | |
| # works around. Only matters if the plugin pulls in catalogs. | |
| try: | |
| from tscat.base import backend as _b | |
| _b() | |
| except ImportError: | |
| pass | |
| plugin_pkg = "${{ matrix.plugin.pkg }}" | |
| mod = importlib.import_module(plugin_pkg) | |
| assert hasattr(mod, "load"), f"{plugin_pkg} has no load() entry point" | |
| from SciQLop.core.ui.mainwindow import SciQLopMainWindow | |
| mw = SciQLopMainWindow() | |
| result = mod.load(mw) | |
| print(f"OK — {plugin_pkg}.load() returned {type(result).__name__ if result is not None else 'None'}") | |
| PY |