mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-09-08 04:00:15 +00:00
Replace the static biomedical category key in Explorer with a live node color legend derived from the active display graph, sharing the canvas's baseColor -> color -> theme fallback resolver. - Preserve original semantic colors on focused display clones via `semanticBaseColor` so interaction styling (selection, path, neighbor highlights) does not bleed into the legend. - Suppress the semantic legend while distance visualization modes are active. - Refactor plugin fallback legend panels to use the shared legend builder with composite (group, color) keys. - Consolidate duplicate `"test:graph-workspace"` scripts in `explorer/package.json`, recovering 26 previously shadowed tests across markdown and explorer capability suites. - Add `tests/graphColorLegend.test.ts` to workspace test runs and wire `test:graph-legend-e2e` into `.github/workflows/ci.yml`. - Closes #1479
174 lines
7.9 KiB
YAML
174 lines
7.9 KiB
YAML
name: CI
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
paths-ignore:
|
|
- 'docs/**'
|
|
- 'docs_check.py'
|
|
- '**/*.md'
|
|
pull_request:
|
|
branches: [main]
|
|
|
|
jobs:
|
|
# Detect whether this PR touches any source files (non-docs/non-markdown).
|
|
# The result drives the `build` job's `if:` condition so that:
|
|
# - docs-only PRs: `build` is skipped (satisfies the required check).
|
|
# - code PRs: `build` runs exactly as before.
|
|
# Push events (to main) keep their own paths-ignore above and never reach
|
|
# this job, so the push optimization is unaffected.
|
|
changes:
|
|
runs-on: ubuntu-latest
|
|
# Only needed for pull_request events; push events are pre-filtered above.
|
|
if: github.event_name == 'pull_request'
|
|
outputs:
|
|
src: ${{ steps.filter.outputs.src }}
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
# Fetch enough history to compute the merge base against the PR base.
|
|
fetch-depth: 0
|
|
- name: Check for source changes
|
|
id: filter
|
|
run: |
|
|
# List files changed in this PR relative to the true merge base.
|
|
# Using three-dot merge-base diff so changes on the base branch that
|
|
# are not part of this PR do not appear in the file list.
|
|
# If every changed file matches docs/** or *.md (any depth) or
|
|
# docs_check.py, this is a docs-only PR and src=false; otherwise
|
|
# src=true.
|
|
BASE="${{ github.event.pull_request.base.sha }}"
|
|
HEAD="${{ github.event.pull_request.head.sha }}"
|
|
MERGE_BASE=$(git merge-base "$BASE" "$HEAD")
|
|
CHANGED=$(git diff --name-only "$MERGE_BASE" "$HEAD")
|
|
echo "Changed files:"
|
|
echo "$CHANGED"
|
|
NON_DOCS=$(echo "$CHANGED" | grep -Ev '^(docs/|docs_check\.py|.*\.md$)' || true)
|
|
if [ -n "$NON_DOCS" ]; then
|
|
echo "src=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "src=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
build:
|
|
needs: [changes]
|
|
# For pull_request events:
|
|
# - skip only when changes ran successfully and explicitly set src=false
|
|
# (i.e. a confirmed docs-only PR).
|
|
# - run when changes succeeded with src=true (source changes present).
|
|
# - run when changes failed or was cancelled (fail-closed: missing output
|
|
# must not silently skip the build).
|
|
# For push/non-PR events: changes is skipped; always() prevents the build
|
|
# from being skipped due to a skipped needs dependency.
|
|
if: >-
|
|
always() && (
|
|
github.event_name != 'pull_request' ||
|
|
needs.changes.result != 'success' ||
|
|
needs.changes.outputs.src == 'true'
|
|
)
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
|
|
with:
|
|
python-version: '3.11'
|
|
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
|
|
with:
|
|
node-version: '20'
|
|
cache: 'npm'
|
|
cache-dependency-path: explorer/package-lock.json
|
|
- name: Install Explorer frontend dependencies
|
|
working-directory: explorer
|
|
run: npm ci
|
|
- name: Install Playwright Chromium
|
|
working-directory: explorer
|
|
run: npx playwright install --with-deps chromium
|
|
- name: Test Explorer frontend
|
|
working-directory: explorer
|
|
run: |
|
|
npm run test:graph-store
|
|
npm run test:graph-workspace
|
|
npm run test:plugin-registry
|
|
npm run test:deterministic-e2e
|
|
npm run test:graph-legend-e2e
|
|
- name: Build Explorer frontend
|
|
working-directory: explorer
|
|
run: npm run build
|
|
- name: Install Explorer backend test dependencies
|
|
run: |
|
|
# Run the deterministic backend path before the all-extras CI
|
|
# environment is installed. The Explorer extra supplies the
|
|
# production API dependencies without importing optional vector
|
|
# providers such as Pinecone during test collection.
|
|
#
|
|
# --no-deps + a separate hash-pinned install (rather than the old
|
|
# `pip install -e ".[explorer]" pytest==9.1.1`) so every fetched
|
|
# package is hash-verified (Scorecard Pinned-Dependencies); the
|
|
# local editable install itself has nothing to hash.
|
|
# .github/requirements/explorer-extra-py311.txt is
|
|
# `uv pip compile pyproject.toml --extra explorer --python-version 3.11 --constraint requirements-ci.txt --generate-hashes`
|
|
# - regenerate it the same way if pyproject.toml's base/explorer
|
|
# deps change. Resolved specifically for this job's python 3.11
|
|
# (see the Dockerfile's explorer-extra-py313.txt for why this
|
|
# can't be shared with python 3.13: audioread needs extra
|
|
# standard-aifc/standard-sunau hashes only on 3.13+).
|
|
#
|
|
# --no-deps only skips *runtime* dependency resolution - `-e .`
|
|
# still does a PEP 517 build, which by default creates an isolated
|
|
# build env and fetches [build-system] requires (setuptools,
|
|
# wheel) completely outside any hash checking. Install
|
|
# pep517-build.txt (pins that exact build-system.requires) first
|
|
# and pass --no-build-isolation so pip reuses those hash-verified
|
|
# copies instead of fetching its own.
|
|
pip install -r .github/requirements/pep517-build.txt --require-hashes
|
|
pip install --no-deps --no-build-isolation -e .
|
|
pip install -r .github/requirements/explorer-extra-py311.txt --require-hashes
|
|
pip install -r .github/requirements/pytest-tool.txt --require-hashes
|
|
- name: Test deterministic Explorer backend path
|
|
run: |
|
|
pytest -q tests/explorer/test_explorer_deterministic_rendering_e2e.py
|
|
- name: Install pinned Python dependencies
|
|
run: |
|
|
pip install -r requirements-ci.txt --require-hashes
|
|
- name: Verify requirements-ci.txt is up to date
|
|
run: |
|
|
pip install -r .github/requirements/uv-tool.txt --require-hashes
|
|
# Re-resolve with the committed file as a constraint: upstream package
|
|
# releases must NOT fail CI (deps only change when pyproject.toml
|
|
# changes intentionally). Compare only version lines (pkg==ver),
|
|
# ignoring the -c constraint comments and the `\` line continuations
|
|
# that --generate-hashes emits.
|
|
uv pip compile pyproject.toml --python-version 3.11 --extra all \
|
|
--constraint requirements-ci.txt -o /tmp/requirements-ci-check.txt
|
|
diff \
|
|
<(grep -E '^[a-zA-Z0-9._-]+==' requirements-ci.txt | sed 's/ \\$//') \
|
|
<(grep -E '^[a-zA-Z0-9._-]+==' /tmp/requirements-ci-check.txt)
|
|
# build is a dev-time dependency; wheel is build-time only (neither is
|
|
# in requirements-ci.txt) — install the same pinned versions
|
|
# [build-system] declares so --no-isolation works below.
|
|
- run: pip install -r .github/requirements/build-tools.txt --require-hashes
|
|
- name: Build package (no isolation — pinned deps)
|
|
run: python -m build --no-isolation
|
|
- name: Verify Explorer frontend is packaged
|
|
run: |
|
|
python - <<'PY'
|
|
import zipfile
|
|
from pathlib import Path
|
|
|
|
wheels = list(Path("dist").glob("*.whl"))
|
|
assert wheels, "No wheel was built"
|
|
|
|
with zipfile.ZipFile(wheels[0]) as wheel:
|
|
names = set(wheel.namelist())
|
|
|
|
assert "semantica/static/index.html" in names, "Explorer index.html missing from wheel"
|
|
assert any(name.startswith("semantica/static/assets/") for name in names), "Explorer assets missing from wheel"
|
|
|
|
print("Explorer frontend is packaged")
|
|
PY
|
|
- name: Run Google ADK Integration Tests
|
|
run: pytest tests/integrations/google_adk/
|