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
16 changes: 15 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,20 @@ jobs:
echo "tag=$PACKAGE/v$NEW_VERSION" >> $GITHUB_OUTPUT
fi

# check-extra-pins requires root extras to match the member version.
# Rewrite those pins (and the same >= pins in downstream libs) in the
# same commit as the version bump so main CI stays green after a release.
# Verify walks the same files Sync writes, scoped to PACKAGE/VERSION.
- name: Sync workspace dependency pins
env:
VERSION: ${{ steps.bump.outputs.new_version }}
run: make bump-workspace-pins

- name: Verify extra pins
env:
VERSION: ${{ steps.bump.outputs.new_version }}
run: make check-workspace-pins

- name: Update lockfile
run: uv lock

Expand All @@ -181,7 +195,7 @@ jobs:
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add "$PKG_DIR/pyproject.toml" "uv.lock"
git add "$PKG_DIR/pyproject.toml" "uv.lock" "pyproject.toml" libs/*/pyproject.toml
git commit -m "chore($PACKAGE): bump version to $NEW_VERSION"

- name: Push to main
Expand Down
13 changes: 12 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ LIBS := giskard-core giskard-llm giskard-agents giskard-checks giskard-scan
# "test the metapackage" means "test everything it pins", i.e. all of LIBS.
METAPACKAGE := giskard
PACKAGE ?= # Optional package to test (e.g., giskard-core, giskard-agents, giskard-checks)
VERSION ?= # Optional, for bump-workspace-pins (e.g. VERSION=1.0.3)
AGENT_NAME ?= # Optional, for setup-for-agents telemetry
REASON ?= # Optional, for setup-for-agents telemetry

Expand Down Expand Up @@ -105,7 +106,7 @@ test-unit-minimal: ## Run unit tests on minimal deps (no provider SDKs), optiona
$(foreach lib,$(TEST_LIBS),uv run pytest libs/$(lib) -m "not functional" &&) true

test-examples: ## Run canonical examples and README snippet lint
uv run pytest examples tools/test_lint_readme_snippets.py -q
uv run pytest examples tools -q
uv run python tools/lint_readme_snippets.py

test-no-providers: ## Run tests that verify behavior when provider SDKs are missing
Expand Down Expand Up @@ -208,6 +209,16 @@ check-notices: ## Check that THIRD_PARTY_NOTICES.md is up to date (run make gene
check-extra-pins: ## Assert root pyproject lower bounds match workspace member versions
uv run python tools/check_extra_pins.py

check-workspace-pins: ## Assert PACKAGE pins equal VERSION in root and libs (used by the release workflow)
@test -n "$(PACKAGE)" || { echo "PACKAGE is required (e.g. PACKAGE=giskard-checks VERSION=1.0.3)"; exit 1; }
@test -n "$(VERSION)" || { echo "VERSION is required (e.g. PACKAGE=giskard-checks VERSION=1.0.3)"; exit 1; }
uv run python tools/check_extra_pins.py "$(PACKAGE)" "$(VERSION)"

bump-workspace-pins: ## Rewrite >= pins for PACKAGE to VERSION (used by the release workflow)
@test -n "$(PACKAGE)" || { echo "PACKAGE is required (e.g. PACKAGE=giskard-checks VERSION=1.0.3)"; exit 1; }
@test -n "$(VERSION)" || { echo "VERSION is required (e.g. PACKAGE=giskard-checks VERSION=1.0.3)"; exit 1; }
uv run python tools/bump_workspace_pins.py "$(PACKAGE)" "$(VERSION)"

check: lint check-format check-compat typecheck security check-licenses check-notices check-extra-pins ## Run all checks

clean: ## Clean up build artifacts and caches
Expand Down
4 changes: 2 additions & 2 deletions THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,14 @@ Find a list of packages below
- License: MIT License
- Compatible: True

### boto3-1.43.80
### boto3-1.43.81

- HomePage: https://github.com/boto/boto3
- Author: Amazon Web Services
- License: Apache-2.0
- Compatible: True

### botocore-1.43.80
### botocore-1.43.81

- HomePage: https://github.com/boto/botocore
- Author: Amazon Web Services
Expand Down
2 changes: 1 addition & 1 deletion libs/giskard-scan/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ license = { text = "Apache Software License 2.0" }
authors = [{ name = "Giskard R&D", email = "rnd@giskard.ai" }]
requires-python = ">=3.12"
dependencies = [
"giskard-checks>=1.0.2,<2",
"giskard-checks>=1.0.3,<2",
"giskard-agents>=1.0.2,<2",
"numpy>=2.4.1,<3",
"huggingface-hub>=1.11.0,<2",
Expand Down
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ classifiers = [
"Programming Language :: Python :: 3.14",
]

dependencies = ["giskard-checks>=1.0.2,<2"]
dependencies = ["giskard-checks>=1.0.3,<2"]

requires-python = ">=3.12"

Expand All @@ -34,7 +34,7 @@ azure = ["giskard-llm[azure]>=1.0.0,<2"]
litellm = ["giskard-agents[litellm]>=1.0.2,<2"]

# Optional checks dependencies
regorus = ["giskard-checks[regorus]>=1.0.2,<2"]
regorus = ["giskard-checks[regorus]>=1.0.3,<2"]

# Optional giskard libs
scan = ["giskard-scan>=1.0.0,<2"]
Expand All @@ -45,7 +45,7 @@ deepteam = ["giskard-scan[deepteam]>=1.0.0,<2"] # Heavy dep, not included by def

# Aggregated packages
all-llms = ["giskard-llm[all]>=1.0.0,<2"] # Install all native LLM providers
all-checks = ["giskard-checks[all]>=1.0.2,<2"] # Install all optional checks dependencies
all-checks = ["giskard-checks[all]>=1.0.3,<2"] # Install all optional checks dependencies
full = ["giskard[all-llms,all-checks,scan,litellm]"]

[project.urls]
Expand Down
120 changes: 120 additions & 0 deletions tools/bump_workspace_pins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
"""Rewrite >= lower bounds for a workspace package across pyproject files.

Used by the release workflow after ``uv version`` so root extras (and
downstream lib pins) stay aligned with the member version that
``check_extra_pins PACKAGE VERSION`` enforces.
"""

import re
import sys
from pathlib import Path

from packaging.utils import canonicalize_name
from packaging.version import InvalidVersion, Version

REPO_ROOT = Path(__file__).resolve().parents[1]

# PEP 508 name + optional extras + >= lower bound. Trailing upper bounds,
# markers, and comments are left untouched.
_PIN_RE = re.compile(
r"(?P<name>[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?)"
r"(?P<extra>\[[^\]]+\])?"
r"(?P<op>\s*>=\s*)"
r"(?P<version>[^,<\"'\s]+)"
)


def rewrite_text(text: str, package: str, new_version: str) -> tuple[str, int]:
"""Replace ``>=`` pins for ``package`` in a pyproject document.

Parameters
----------
text : str
Raw ``pyproject.toml`` contents.
package : str
Distribution name to update (hyphen or underscore form).
new_version : str
Replacement lower bound (PEP 440).

Returns
-------
tuple[str, int]
Rewritten text and the number of pins that named ``package``.
"""
target = canonicalize_name(package)
count = 0

def repl(match: re.Match[str]) -> str:
nonlocal count
if canonicalize_name(match.group("name")) != target:
return match.group(0)
count += 1
extra = match.group("extra") or ""
return f"{match.group('name')}{extra}{match.group('op')}{new_version}"

return _PIN_RE.sub(repl, text), count


def pyproject_paths(repo_root: Path) -> list[Path]:
"""Return root and ``libs/*/pyproject.toml`` paths that exist."""
paths = [repo_root / "pyproject.toml"]
libs = repo_root / "libs"
if libs.is_dir():
paths.extend(sorted(libs.glob("*/pyproject.toml")))
return [path for path in paths if path.is_file()]


def bump_pins(
repo_root: Path, package: str, new_version: str
) -> list[tuple[Path, int]]:
"""Write updated pins for ``package`` under ``repo_root``.

Parameters
----------
repo_root : Path
Monorepo root containing ``pyproject.toml`` and ``libs/``.
package : str
Distribution name whose ``>=`` pins should move.
new_version : str
Replacement lower bound (PEP 440).

Returns
-------
list[tuple[Path, int]]
Files that changed, with the pin count in each file.
"""
try:
Version(new_version)
except InvalidVersion as exc:
raise SystemExit(f"invalid version {new_version!r}: {exc}") from exc

results: list[tuple[Path, int]] = []
for path in pyproject_paths(repo_root):
original = path.read_text(encoding="utf-8")
updated, count = rewrite_text(original, package, new_version)
if updated == original:
continue
path.write_text(updated, encoding="utf-8")
results.append((path, count))
return results


def main(argv: list[str] | None = None) -> int:
"""Rewrite pins for ``PACKAGE VERSION``. Returns a process exit code."""
args = sys.argv[1:] if argv is None else argv
if len(args) != 2:
print("usage: bump_workspace_pins.py PACKAGE VERSION", file=sys.stderr)
return 2

package, version = args
results = bump_pins(REPO_ROOT, package, version)
if not results:
print(f"No {package} pins to update.")
return 0
for path, count in results:
print(f"Updated {count} pin(s) in {path.relative_to(REPO_ROOT)}")
return 0


if __name__ == "__main__":
raise SystemExit(main())
Loading
Loading