Skip to content
Open
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
2 changes: 2 additions & 0 deletions hindsight-dev/hindsight_dev/generate_changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class IntegrationMeta:
"pydantic-ai": IntegrationMeta("hindsight-pydantic-ai", "Pydantic AI"),
"crewai": IntegrationMeta("hindsight-crewai", "CrewAI"),
"agent-framework": IntegrationMeta("hindsight-agent-framework", "Microsoft Agent Framework"),
"agno": IntegrationMeta("hindsight-agno", "Agno"),
"ag2": IntegrationMeta("hindsight-ag2"),
"ai-sdk": IntegrationMeta("@vectorize-io/hindsight-ai-sdk", "AI SDK"),
"chat": IntegrationMeta("@vectorize-io/hindsight-chat", "Chat SDK"),
Expand Down Expand Up @@ -76,6 +77,7 @@ class IntegrationMeta:
"roo-code": IntegrationMeta("hindsight-roo-code", "Roo Code"),
"omo": IntegrationMeta("hindsight-omo", "OMO"),
"composio": IntegrationMeta("hindsight-composio", "Composio"),
"continue": IntegrationMeta("hindsight-continue", "Continue"),
}

VALID_INTEGRATIONS = list(INTEGRATIONS.keys())
Expand Down
63 changes: 63 additions & 0 deletions hindsight-dev/tests/test_generate_changelog_registry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""Regression tests for integration changelog registry coverage."""

import subprocess
import tomllib
from pathlib import Path

from hindsight_dev.generate_changelog import INTEGRATIONS

REPO_ROOT = Path(__file__).resolve().parents[2]
RELEASE_SCRIPT = REPO_ROOT / "scripts" / "release-integration.sh"
NEW_PYTHON_INTEGRATIONS = {"agno", "continue"}


def _release_script_integrations():
result = subprocess.run(
["bash", str(RELEASE_SCRIPT), "--list-integrations"],
check=True,
capture_output=True,
cwd=REPO_ROOT,
text=True,
)
return result.stdout.splitlines()


def _validate_release_path(slug):
subprocess.run(
["bash", str(RELEASE_SCRIPT), "--validate-only", slug],
check=True,
capture_output=True,
cwd=REPO_ROOT,
text=True,
)


def test_release_script_integrations_match_changelog_metadata():
release_integrations = _release_script_integrations()

assert len(release_integrations) == len(set(release_integrations))
assert set(release_integrations) == set(INTEGRATIONS)
assert NEW_PYTHON_INTEGRATIONS <= set(release_integrations)


def test_python_integration_metadata_matches_package_manifests():
pyproject_slugs = {path.parent.name for path in (REPO_ROOT / "hindsight-integrations").glob("*/pyproject.toml")}
assert NEW_PYTHON_INTEGRATIONS <= pyproject_slugs

for slug, meta in INTEGRATIONS.items():
pyproject = REPO_ROOT / "hindsight-integrations" / slug / "pyproject.toml"
if not pyproject.exists():
continue
manifest = tomllib.loads(pyproject.read_text())

assert meta.package_name == manifest["project"]["name"]


def test_new_integration_display_names_match_user_facing_brands():
assert INTEGRATIONS["agno"].display_name == "Agno"
assert INTEGRATIONS["continue"].display_name == "Continue"


def test_new_integration_release_paths_validate_before_mutation():
for slug in NEW_PYTHON_INTEGRATIONS:
_validate_release_path(slug)
77 changes: 64 additions & 13 deletions scripts/release-integration.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,26 @@ usage() {
exit 1
}

if [ -z "$1" ] || [ -z "$2" ]; then
if [ "${1:-}" = "--list-integrations" ] && [ "$#" -eq 1 ]; then
printf "%s\n" "${VALID_INTEGRATIONS[@]}"
exit 0
fi

VALIDATE_ONLY=false
if [ "${1:-}" = "--validate-only" ]; then
VALIDATE_ONLY=true
shift
if [ -z "${1:-}" ] || [ "$#" -ne 1 ]; then
usage
fi
fi

if [ -z "$1" ] || { [ "$VALIDATE_ONLY" = false ] && [ -z "$2" ]; }; then
usage
fi

INTEGRATION=$1
VERSION_ARG=$2
VERSION_ARG=${2:-}

# Validate integration name
VALID=false
Expand Down Expand Up @@ -77,6 +91,54 @@ bump_version() {
esac
}

validate_manifest_version_field() {
local manifest=$1
python3 - "$manifest" <<'PY'
import json
import sys
from pathlib import Path

path = Path(sys.argv[1])
if path.name == "pyproject.toml":
import tomllib

data = tomllib.loads(path.read_text())
version = data.get("project", {}).get("version")
else:
data = json.loads(path.read_text())
version = data.get("version")

if not isinstance(version, str) or not version:
raise SystemExit(f"Could not read a top-level release version from {path}")
PY
}

INTEGRATION_DIR="hindsight-integrations/$INTEGRATION"

if [ ! -d "$INTEGRATION_DIR" ]; then
print_error "Integration directory not found: $INTEGRATION_DIR"
exit 1
fi

if [ -f "$INTEGRATION_DIR/pyproject.toml" ]; then
MANIFEST_PATH="$INTEGRATION_DIR/pyproject.toml"
elif [ -f "$INTEGRATION_DIR/package.json" ]; then
MANIFEST_PATH="$INTEGRATION_DIR/package.json"
elif [ -f "$INTEGRATION_DIR/.claude-plugin/plugin.json" ]; then
MANIFEST_PATH="$INTEGRATION_DIR/.claude-plugin/plugin.json"
elif [ -f "$INTEGRATION_DIR/settings.json" ] && grep -q '"version"' "$INTEGRATION_DIR/settings.json"; then
MANIFEST_PATH="$INTEGRATION_DIR/settings.json"
else
print_error "No pyproject.toml, package.json, plugin.json, or versioned settings.json found in $INTEGRATION_DIR"
exit 1
fi

if [ "$VALIDATE_ONLY" = true ]; then
validate_manifest_version_field "$MANIFEST_PATH"
print_info "Validated $INTEGRATION release path via $MANIFEST_PATH"
exit 0
fi

# Resolve version: either an explicit semver or a bump keyword
if [[ "$VERSION_ARG" =~ ^(patch|minor|major)$ ]]; then
CURRENT_VERSION=$(get_current_version)
Expand Down Expand Up @@ -135,14 +197,6 @@ if [ -z "$OPENAI_API_KEY" ]; then
exit 1
fi

# Determine integration type and update version
INTEGRATION_DIR="hindsight-integrations/$INTEGRATION"

if [ ! -d "$INTEGRATION_DIR" ]; then
print_error "Integration directory not found: $INTEGRATION_DIR"
exit 1
fi

if [ -f "$INTEGRATION_DIR/pyproject.toml" ]; then
print_info "Updating version in $INTEGRATION_DIR/pyproject.toml"
sed -i.bak "s/^version = \".*\"/version = \"$VERSION\"/" "$INTEGRATION_DIR/pyproject.toml"
Expand All @@ -159,9 +213,6 @@ elif [ -f "$INTEGRATION_DIR/settings.json" ] && grep -q '"version"' "$INTEGRATIO
print_info "Updating version in $INTEGRATION_DIR/settings.json"
sed -i.bak "s/\"version\": \".*\"/\"version\": \"$VERSION\"/" "$INTEGRATION_DIR/settings.json"
rm "$INTEGRATION_DIR/settings.json.bak"
else
print_error "No pyproject.toml, package.json, plugin.json, or versioned settings.json found in $INTEGRATION_DIR"
exit 1
fi

# Generate changelog entry using LLM
Expand Down