Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,9 @@ jobs:
wheels = sorted(pathlib.Path("dist").glob("*.whl"))

# One wheel per platform and supported interpreter. The interpreters are the classifiers of
# pyproject.toml, which test-python-bindings.yml's matrix mirrors; the four platforms are
# the matrix platforms. Adding either to the matrix changes the expected count here.
# pyproject.toml, which the full matrix of scripts/select_matrix.py mirrors (the release runs the full
# matrix, not the small pull request one); the four platforms are the matrix platforms. Adding either to
# the matrix changes the expected count here.
prefix = "Programming Language :: Python :: 3."
classifiers = tomllib.load(open("pyproject.toml", "rb"))["project"]["classifiers"]
pythons = [c.rsplit(" ", 1)[1] for c in classifiers if c.startswith(prefix)]
Expand Down
45 changes: 21 additions & 24 deletions .github/workflows/test-python-bindings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,25 @@ jobs:
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
outputs:
arcadedb-tag: ${{ steps.jars.outputs.arcadedb-tag }}
matrix: ${{ steps.matrix.outputs.matrix }}
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

# The platform x Python legs of this run (scripts/select_matrix.py): a small matrix on
# pull requests, the full one on every other event. The organisation shares one runner
# cap with ArcadeData/arcadedb, so a pull request does not run every combination.
# Done first, so a failure here costs no Docker pull.
- name: Select the test matrix
id: matrix
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
run: |
matrix="$(python3 scripts/select_matrix.py bindings --event "$EVENT_NAME")"
echo "$matrix"
echo "matrix=$matrix" >> "$GITHUB_OUTPUT"

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1

Expand Down Expand Up @@ -250,30 +265,12 @@ jobs:
strategy:
# Don't cancel other matrix jobs if one fails
fail-fast: false
matrix:
python-version:
- '3.10'
- '3.11'
- '3.12'
- '3.13'
- '3.14'
# Temporarily limit to four platforms (skip macOS x86_64, Windows ARM64)
# platform: ['linux/amd64', 'linux/arm64', 'darwin/amd64', 'darwin/arm64', 'windows/amd64', 'windows/arm64']
platform: ['linux/amd64', 'linux/arm64', 'darwin/arm64', 'windows/amd64']
include:
- platform: linux/amd64
runs-on: ubuntu-24.04
- platform: linux/arm64
runs-on: ubuntu-24.04-arm
- platform: darwin/arm64
runs-on: macos-15
- platform: windows/amd64
runs-on: windows-2025
# - platform: darwin/amd64
# runs-on: macos-15-intel
# - platform: windows/arm64
# runs-on: windows-11-arm
# macOS x86_64 and Windows ARM64 temporarily disabled
# Chosen by the "Select the test matrix" step of download-jars from the event that
# started the run (scripts/select_matrix.py holds the platform and Python lists):
# small on pull requests, the full 4 platforms x 5 Pythons on every other event.
# Every leg carries platform, runs-on and python-version, so the job names stay
# "Test arcadedb (<platform>, Python <version>)".
matrix: ${{ fromJSON(needs.download-jars.outputs.matrix) }}

steps:
- name: Checkout code
Expand Down
47 changes: 22 additions & 25 deletions .github/workflows/test-python-examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,25 @@ jobs:
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
outputs:
arcadedb-tag: ${{ steps.jars.outputs.arcadedb-tag }}
matrix: ${{ steps.matrix.outputs.matrix }}
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

# The platform x Python legs of this run (scripts/select_matrix.py): a small matrix on
# pull requests, the full one on every other event. The organisation shares one runner
# cap with ArcadeData/arcadedb, so a pull request does not run every combination.
# Done first, so a failure here costs no Docker pull.
- name: Select the test matrix
id: matrix
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
run: |
matrix="$(python3 scripts/select_matrix.py examples --event "$EVENT_NAME")"
echo "$matrix"
echo "matrix=$matrix" >> "$GITHUB_OUTPUT"

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1

Expand Down Expand Up @@ -163,36 +178,18 @@ jobs:
BUILD_VERSION: ${{ inputs.build-version }}
# Pin the Hugging Face cache inside the workspace so it is cacheable with
# one path on every platform (the default differs per OS). The examples
# embed with sentence-transformers, and this matrix is 20 jobs, so
# embed with sentence-transformers, and the full matrix is 20 jobs, so
# uncached that is 20 independent model downloads per release and 20
# chances for a transient hub outage to fail a release. It has happened.
HF_HOME: ${{ github.workspace }}/.hf-cache
strategy:
fail-fast: false
matrix:
python-version:
- '3.10'
- '3.11'
- '3.12'
- '3.13'
- '3.14'
# Temporarily limit to four platforms (skip macOS x86_64, Windows ARM64)
# platform: ['linux/amd64', 'linux/arm64', 'darwin/amd64', 'darwin/arm64', 'windows/amd64', 'windows/arm64']
platform: ['linux/amd64', 'linux/arm64', 'darwin/arm64', 'windows/amd64']
include:
- platform: linux/amd64
runs-on: ubuntu-24.04
- platform: linux/arm64
runs-on: ubuntu-24.04-arm
- platform: darwin/arm64
runs-on: macos-15
- platform: windows/amd64
runs-on: windows-2025
# - platform: darwin/amd64
# runs-on: macos-15-intel
# - platform: windows/arm64
# runs-on: windows-11-arm
# macOS x86_64 and Windows ARM64 temporarily disabled
# Chosen by the "Select the test matrix" step of download-jars from the event that
# started the run (scripts/select_matrix.py holds the platform and Python lists):
# small on pull requests, the full 4 platforms x 5 Pythons on every other event.
# Every leg carries platform, runs-on and python-version, so the job names stay
# "Test Python Examples (<platform>, Python <version>)".
matrix: ${{ fromJSON(needs.download-jars.outputs.matrix) }}

steps:
- name: Checkout code
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,6 @@ python -m bandit -c pyproject.toml -r examples --severity-level medium --confide

## CI

`.github/workflows/test-python-bindings.yml` builds wheels for linux/amd64, linux/arm64, darwin/arm64, windows/amd64 and tests Python 3.10–3.14; also runs nightly against `arcadedata/arcadedb:latest`. Both workflows accept an `arcadedb-tag` input to pin the image. `test-python-examples.yml` runs `examples/`. A dependency-floor audit resolves extras with `--resolution lowest-direct` for each Python classifier and runs pip-audit, so raise lower bounds when a floor has an advisory.
`.github/workflows/test-python-bindings.yml` builds wheels for linux/amd64, linux/arm64, darwin/arm64, windows/amd64 and tests Python 3.10–3.14; also runs nightly against `arcadedata/arcadedb:latest`. The org shares a runner cap with upstream, so a pull request runs a small matrix (bindings: linux/amd64 on all five Pythons, the other three platforms on 3.10 and 3.14 = 11 legs; examples: all four platforms on 3.14 = 4 legs, 21 checks in all), while push to main, the nightly run, dispatch and the release run all 20 legs of each workflow (46 checks). `scripts/select_matrix.py` holds both lists (`PULL_REQUEST_LEGS`), the first job of each workflow runs it, and `tests/test_select_matrix.py` pins the full matrix; docs page `development/ci.adoc`. Keep the job names `Test arcadedb (<platform>, Python <version>)` unchanged. Both workflows accept an `arcadedb-tag` input to pin the image. `test-python-examples.yml` runs `examples/`. A dependency-floor audit resolves extras with `--resolution lowest-direct` for each Python classifier and runs pip-audit, so raise lower bounds when a floor has an advisory.

`.github/workflows/release.yml` publishes on a bare-version tag (`26.11.1.dev0`, `26.11.1`, `26.11.1.post1`; no `v`, never `aN`/`bN`/`rcN`). Its first job runs `scripts/check_version.py` (the devN/postN counting rule, read-only, fails closed); `scripts/after_tag_verify.sh` checks the finished release. The rule is stated once, on the docs page `development/release.adoc`.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pip install arcadedb # or: uv add arcadedb

This package was published as arcadedb-embedded until 26.10.x; install arcadedb now.

- Python 3.10 to 3.14. CI builds and tests all five versions on every platform below.
- Python 3.10 to 3.14. CI builds and tests all five versions on every platform below for `main`, every night and each release. A pull request runs a smaller selection.
- Linux x86_64 and ARM64, macOS on Apple Silicon, Windows x86_64. One wheel per platform and Python version.
- Import name: `arcadedb`. Optional extras: `arrow`, `pandas`, `vector`.

Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
** xref:how-to/databases-and-queries.adoc[Databases and queries]
** xref:how-to/concurrency.adoc[Concurrency, processes and crashes]
* Development
** xref:development/ci.adoc[Continuous integration]
** xref:development/release.adoc[Release]
39 changes: 39 additions & 0 deletions docs/modules/ROOT/pages/development/ci.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
= Continuous integration
:description: Which platforms and Python versions the CI runs for a pull request, and which for main, the nightly run and a release.

Two workflows test the package: `test-python-bindings.yml` builds a wheel and runs the unit tests, and `test-python-examples.yml` runs the scripts in `examples/`. Both build the wheels on a native runner of each platform.

The package supports four platforms and five Python versions (3.10 to 3.14). That is 20 combinations for each workflow. A pull request does not run all of them, because the organisation shares one runner limit with ArcadeData/arcadedb. Each macOS or Windows job on a pull request delays the upstream jobs too.

== What runs when

The script `scripts/select_matrix.py` chooses the combinations. The first job of each workflow, `Download ArcadeDB JARs`, runs it and passes the result to the test job.

[cols="2,3,3"]
|===
| Event | Unit tests (`Test arcadedb`) | Examples (`Test Python Examples`)

| Pull request
| `linux/amd64` on all five Python versions. `linux/arm64`, `darwin/arm64` and `windows/amd64` on Python 3.10 and 3.14.
| All four platforms on Python 3.14.

| Push to `main`, the nightly run, a manual run, a release
| All 20 combinations.
| All 20 combinations.
|===

A pull request runs 21 checks: 15 test jobs (11 and 4), the two `Download ArcadeDB JARs` jobs, the two summary jobs, `Bandit security scan` and `Dependency floor audit`. The full matrix runs 46.

The names of the test jobs do not change: `Test arcadedb (<platform>, Python <version>)`. A check keeps its history when a pull request runs fewer of them.

A release always runs the full matrix, because `release.yml` expects one wheel for each platform and Python version. The nightly run also tests against the newest `arcadedata/arcadedb:latest` image.

== Other rules

* A pull request that changes only documentation (`docs/**`, `*.adoc`, `CLAUDE.md`, `examples/README.md`, `LICENSE*`) runs nothing.
* A draft pull request skips the platform jobs. Marking it ready for review starts them.
* A new push to a pull request cancels the run it replaces. A run on `main` is never cancelled.

== Change the selection

Edit `PULL_REQUEST_LEGS` in `scripts/select_matrix.py`. The test `tests/test_select_matrix.py` fixes the full matrix at 20 combinations, so a change that shrinks it fails. When you add a Python version, add it to `PYTHONS` in the script and to the classifiers in `pyproject.toml`. A test checks that both lists are the same.
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ Both packages import as `{import-name}`, so an environment holds one of them. Th

== Requirements

* Python 3.10 to 3.14. The wheels' CI runs all five versions on every supported platform.
* Python 3.10 to 3.14. The wheels' CI runs all five versions on every supported platform for `main`, the nightly run and each release. A pull request runs a smaller selection (xref:development/ci.adoc[Continuous integration]).
* Linux (x86_64 and ARM64), macOS on Apple Silicon, or Windows (x86_64).
* No Java installation.

Expand Down
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/installation.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ The package is self-contained. It carries a Java 25 runtime for its platform, so

== Requirements

* Python 3.10 to 3.14. The wheels' CI runs all five versions on every supported platform.
* Python 3.10 to 3.14. The wheels' CI runs all five versions on every supported platform for `main`, the nightly run and each release. A pull request runs a smaller selection (xref:development/ci.adoc[Continuous integration]).
* One of the four platforms below.

Every wheel is platform-specific, built on a native runner of its platform, and carries a JRE for that platform, so pip needs no hint to pick the right one.
Expand Down
104 changes: 104 additions & 0 deletions scripts/select_matrix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/usr/bin/env python3
"""Pick the platform x Python legs a CI workflow runs for the event that started it.

The wheels support four platforms and five Python versions, which is 20 legs per workflow. A
pull request does not need all of them: the organisation shares one runner cap with
ArcadeData/arcadedb, so every extra macOS or Windows leg on a pull request delays upstream too.

- `pull_request` runs the small matrix below.
- Every other event runs the full matrix: a push to main, the nightly schedule, a manual
dispatch, and the release workflow (which calls the workflows as `workflow_call`; the event
name seen there is the caller's, a tag push). The release needs one wheel per platform and
Python version, and `release.yml` counts them.

The selection fails open to the full matrix: an event name this script does not know runs
everything, never less.

usage:
select_matrix.py bindings [--event NAME] # test-python-bindings.yml
select_matrix.py examples [--event NAME] # test-python-examples.yml

`--event` defaults to $GITHUB_EVENT_NAME. The output is one line of JSON for
`strategy.matrix`: {"include": [{"platform": ..., "runs-on": ..., "python-version": ...}, ...]}.
The names of the jobs stay "Test arcadedb (<platform>, Python <version>)", so the history of a
check is comparable before and after the selection.
"""

from __future__ import annotations

import argparse
import json
import os
import sys

# Temporarily limited to four platforms: macOS x86_64 (runner macos-15-intel) and Windows ARM64
# (windows-11-arm) are off. This is the platform column both workflows had before this script.
RUNNERS = {
"linux/amd64": "ubuntu-24.04",
"linux/arm64": "ubuntu-24.04-arm",
"darwin/arm64": "macos-15",
"windows/amd64": "windows-2025",
}

# Every Python the package supports. tests/test_select_matrix.py compares this with the
# classifiers of pyproject.toml, so adding a version there without adding it here fails.
PYTHONS = ("3.10", "3.11", "3.12", "3.13", "3.14")
OLDEST = PYTHONS[0]
NEWEST = PYTHONS[-1]

# The legs of a pull request, per workflow: platform -> Python versions.
#
# bindings: all Pythons on linux/amd64 (the cheap, fast runner and the one most contributors
# use), the oldest and the newest on the three other platforms. A bug that depends on the
# interpreter shows on the ends of the range, and one that depends on the platform shows on
# any version of it.
#
# examples: the newest Python only, on every platform. The examples are slow (torch,
# sentence-transformers), and they carry platform-specific code (`os.name == "nt"` branches in
# examples 07 to 12) and per-platform steps in the workflow (a CPU torch index on macOS, UTF-8
# on Windows), so all four platforms stay.
PULL_REQUEST_LEGS = {
"bindings": {
"linux/amd64": PYTHONS,
"linux/arm64": (OLDEST, NEWEST),
"darwin/arm64": (OLDEST, NEWEST),
"windows/amd64": (OLDEST, NEWEST),
},
"examples": {platform: (NEWEST,) for platform in RUNNERS},
}


def _legs(per_platform: dict[str, tuple[str, ...]]) -> list[dict[str, str]]:
return [
{"platform": platform, "runs-on": RUNNERS[platform], "python-version": python}
for platform in RUNNERS
for python in per_platform.get(platform, ())
]


def select(workflow: str, event: str) -> dict[str, list[dict[str, str]]]:
"""The `strategy.matrix` of `workflow` ("bindings" or "examples") for `event`."""
if workflow not in PULL_REQUEST_LEGS:
raise ValueError(
f"unknown workflow {workflow!r}; use one of {sorted(PULL_REQUEST_LEGS)}"
)
if event == "pull_request":
return {"include": _legs(PULL_REQUEST_LEGS[workflow])}
return {"include": _legs({platform: PYTHONS for platform in RUNNERS})}


def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description=__doc__.split("\n\n")[0])
parser.add_argument("workflow", choices=sorted(PULL_REQUEST_LEGS))
parser.add_argument(
"--event",
default=os.environ.get("GITHUB_EVENT_NAME", ""),
help="the event that started the workflow (default: $GITHUB_EVENT_NAME)",
)
args = parser.parse_args(argv)
print(json.dumps(select(args.workflow, args.event), separators=(",", ":")))
return 0


if __name__ == "__main__":
sys.exit(main())
Loading
Loading