Browse Source

refactor: improve plugin version validation to support full semantic versioning (#25161)

Signed-off-by: -LAN- <laipz8200@outlook.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
tags/2.0.0-beta.2^2
-LAN- 1 month ago
parent
commit
e78f1cdc6a
No account linked to committer's email address

+ 24
- 3
api/core/plugin/entities/plugin.py View File

from collections.abc import Mapping from collections.abc import Mapping
from typing import Any, Optional from typing import Any, Optional


from pydantic import BaseModel, Field, model_validator
from packaging.version import InvalidVersion, Version
from pydantic import BaseModel, Field, field_validator, model_validator
from werkzeug.exceptions import NotFound from werkzeug.exceptions import NotFound


from core.agent.plugin_entities import AgentStrategyProviderEntity from core.agent.plugin_entities import AgentStrategyProviderEntity
endpoints: Optional[list[str]] = Field(default_factory=list[str]) endpoints: Optional[list[str]] = Field(default_factory=list[str])


class Meta(BaseModel): class Meta(BaseModel):
minimum_dify_version: Optional[str] = Field(default=None, pattern=r"^\d{1,4}(\.\d{1,4}){1,3}(-\w{1,16})?$")
minimum_dify_version: Optional[str] = Field(default=None)
version: Optional[str] = Field(default=None) version: Optional[str] = Field(default=None)


version: str = Field(..., pattern=r"^\d{1,4}(\.\d{1,4}){1,3}(-\w{1,16})?$")
@field_validator("minimum_dify_version")
@classmethod
def validate_minimum_dify_version(cls, v: Optional[str]) -> Optional[str]:
if v is None:
return v
try:
Version(v)
return v
except InvalidVersion as e:
raise ValueError(f"Invalid version format: {v}") from e

version: str = Field(...)
author: Optional[str] = Field(..., pattern=r"^[a-zA-Z0-9_-]{1,64}$") author: Optional[str] = Field(..., pattern=r"^[a-zA-Z0-9_-]{1,64}$")
name: str = Field(..., pattern=r"^[a-z0-9_-]{1,128}$") name: str = Field(..., pattern=r"^[a-z0-9_-]{1,128}$")
description: I18nObject description: I18nObject
agent_strategy: Optional[AgentStrategyProviderEntity] = None agent_strategy: Optional[AgentStrategyProviderEntity] = None
meta: Meta meta: Meta


@field_validator("version")
@classmethod
def validate_version(cls, v: str) -> str:
try:
Version(v)
return v
except InvalidVersion as e:
raise ValueError(f"Invalid version format: {v}") from e

@model_validator(mode="before") @model_validator(mode="before")
@classmethod @classmethod
def validate_category(cls, values: dict) -> dict: def validate_category(cls, values: dict) -> dict:

+ 4
- 3
api/pyproject.toml View File

"weave~=0.51.0", "weave~=0.51.0",
"yarl~=1.18.3", "yarl~=1.18.3",
"webvtt-py~=0.5.1", "webvtt-py~=0.5.1",
"sseclient-py>=1.8.0",
"httpx-sse>=0.4.0",
"sseclient-py~=1.8.0",
"httpx-sse~=0.4.0",
"sendgrid~=6.12.3", "sendgrid~=6.12.3",
"flask-restx>=1.3.0",
"flask-restx~=1.3.0",
"packaging~=23.2",
] ]
# Before adding new dependency, consider place it in # Before adding new dependency, consider place it in
# alphabet order (a-z) and suitable group. # alphabet order (a-z) and suitable group.

+ 16
- 5
api/tests/test_containers_integration_tests/services/test_webapp_auth_service.py View File

tuple: (account, tenant) - Created account and tenant instances tuple: (account, tenant) - Created account and tenant instances
""" """
fake = Faker() fake = Faker()
import uuid


# Create account
# Create account with unique email to avoid collisions
unique_email = f"test_{uuid.uuid4().hex[:8]}@example.com"
account = Account( account = Account(
email=fake.email(),
email=unique_email,
name=fake.name(), name=fake.name(),
interface_language="en-US", interface_language="en-US",
status="active", status="active",
password = fake.password(length=12) password = fake.password(length=12)


# Create account with password # Create account with password
import uuid

unique_email = f"test_{uuid.uuid4().hex[:8]}@example.com"
account = Account( account = Account(
email=fake.email(),
email=unique_email,
name=fake.name(), name=fake.name(),
interface_language="en-US", interface_language="en-US",
status="active", status="active",
""" """
# Arrange: Create account without password # Arrange: Create account without password
fake = Faker() fake = Faker()
import uuid

unique_email = f"test_{uuid.uuid4().hex[:8]}@example.com"


account = Account( account = Account(
email=fake.email(),
email=unique_email,
name=fake.name(), name=fake.name(),
interface_language="en-US", interface_language="en-US",
status="active", status="active",
""" """
# Arrange: Create banned account # Arrange: Create banned account
fake = Faker() fake = Faker()
import uuid

unique_email = f"test_{uuid.uuid4().hex[:8]}@example.com"


account = Account( account = Account(
email=fake.email(),
email=unique_email,
name=fake.name(), name=fake.name(),
interface_language="en-US", interface_language="en-US",
status=AccountStatus.BANNED.value, status=AccountStatus.BANNED.value,

+ 5
- 3
api/uv.lock View File

{ name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-semantic-conventions" },
{ name = "opentelemetry-util-http" }, { name = "opentelemetry-util-http" },
{ name = "opik" }, { name = "opik" },
{ name = "packaging" },
{ name = "pandas", extra = ["excel", "output-formatting", "performance"] }, { name = "pandas", extra = ["excel", "output-formatting", "performance"] },
{ name = "pandoc" }, { name = "pandoc" },
{ name = "psycogreen" }, { name = "psycogreen" },
{ name = "flask-login", specifier = "~=0.6.3" }, { name = "flask-login", specifier = "~=0.6.3" },
{ name = "flask-migrate", specifier = "~=4.0.7" }, { name = "flask-migrate", specifier = "~=4.0.7" },
{ name = "flask-orjson", specifier = "~=2.0.0" }, { name = "flask-orjson", specifier = "~=2.0.0" },
{ name = "flask-restx", specifier = ">=1.3.0" },
{ name = "flask-restx", specifier = "~=1.3.0" },
{ name = "flask-sqlalchemy", specifier = "~=3.1.1" }, { name = "flask-sqlalchemy", specifier = "~=3.1.1" },
{ name = "gevent", specifier = "~=24.11.1" }, { name = "gevent", specifier = "~=24.11.1" },
{ name = "gmpy2", specifier = "~=2.2.1" }, { name = "gmpy2", specifier = "~=2.2.1" },
{ name = "googleapis-common-protos", specifier = "==1.63.0" }, { name = "googleapis-common-protos", specifier = "==1.63.0" },
{ name = "gunicorn", specifier = "~=23.0.0" }, { name = "gunicorn", specifier = "~=23.0.0" },
{ name = "httpx", extras = ["socks"], specifier = "~=0.27.0" }, { name = "httpx", extras = ["socks"], specifier = "~=0.27.0" },
{ name = "httpx-sse", specifier = ">=0.4.0" },
{ name = "httpx-sse", specifier = "~=0.4.0" },
{ name = "jieba", specifier = "==0.42.1" }, { name = "jieba", specifier = "==0.42.1" },
{ name = "json-repair", specifier = ">=0.41.1" }, { name = "json-repair", specifier = ">=0.41.1" },
{ name = "langfuse", specifier = "~=2.51.3" }, { name = "langfuse", specifier = "~=2.51.3" },
{ name = "opentelemetry-semantic-conventions", specifier = "==0.48b0" }, { name = "opentelemetry-semantic-conventions", specifier = "==0.48b0" },
{ name = "opentelemetry-util-http", specifier = "==0.48b0" }, { name = "opentelemetry-util-http", specifier = "==0.48b0" },
{ name = "opik", specifier = "~=1.7.25" }, { name = "opik", specifier = "~=1.7.25" },
{ name = "packaging", specifier = "~=23.2" },
{ name = "pandas", extras = ["excel", "output-formatting", "performance"], specifier = "~=2.2.2" }, { name = "pandas", extras = ["excel", "output-formatting", "performance"], specifier = "~=2.2.2" },
{ name = "pandoc", specifier = "~=2.4" }, { name = "pandoc", specifier = "~=2.4" },
{ name = "psycogreen", specifier = "~=1.0.2" }, { name = "psycogreen", specifier = "~=1.0.2" },
{ name = "sendgrid", specifier = "~=6.12.3" }, { name = "sendgrid", specifier = "~=6.12.3" },
{ name = "sentry-sdk", extras = ["flask"], specifier = "~=2.28.0" }, { name = "sentry-sdk", extras = ["flask"], specifier = "~=2.28.0" },
{ name = "sqlalchemy", specifier = "~=2.0.29" }, { name = "sqlalchemy", specifier = "~=2.0.29" },
{ name = "sseclient-py", specifier = ">=1.8.0" },
{ name = "sseclient-py", specifier = "~=1.8.0" },
{ name = "starlette", specifier = "==0.47.2" }, { name = "starlette", specifier = "==0.47.2" },
{ name = "tiktoken", specifier = "~=0.9.0" }, { name = "tiktoken", specifier = "~=0.9.0" },
{ name = "transformers", specifier = "~=4.53.0" }, { name = "transformers", specifier = "~=4.53.0" },

Loading…
Cancel
Save