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>
This commit is contained in:
@@ -4,7 +4,8 @@ import re
|
||||
from collections.abc import Mapping
|
||||
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 core.agent.plugin_entities import AgentStrategyProviderEntity
|
||||
@@ -71,10 +72,21 @@ class PluginDeclaration(BaseModel):
|
||||
endpoints: Optional[list[str]] = Field(default_factory=list[str])
|
||||
|
||||
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: 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}$")
|
||||
name: str = Field(..., pattern=r"^[a-z0-9_-]{1,128}$")
|
||||
description: I18nObject
|
||||
@@ -94,6 +106,15 @@ class PluginDeclaration(BaseModel):
|
||||
agent_strategy: Optional[AgentStrategyProviderEntity] = None
|
||||
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")
|
||||
@classmethod
|
||||
def validate_category(cls, values: dict) -> dict:
|
||||
|
@@ -84,10 +84,11 @@ dependencies = [
|
||||
"weave~=0.51.0",
|
||||
"yarl~=1.18.3",
|
||||
"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",
|
||||
"flask-restx>=1.3.0",
|
||||
"flask-restx~=1.3.0",
|
||||
"packaging~=23.2",
|
||||
]
|
||||
# Before adding new dependency, consider place it in
|
||||
# alphabet order (a-z) and suitable group.
|
||||
|
@@ -57,10 +57,12 @@ class TestWebAppAuthService:
|
||||
tuple: (account, tenant) - Created account and tenant instances
|
||||
"""
|
||||
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(
|
||||
email=fake.email(),
|
||||
email=unique_email,
|
||||
name=fake.name(),
|
||||
interface_language="en-US",
|
||||
status="active",
|
||||
@@ -109,8 +111,11 @@ class TestWebAppAuthService:
|
||||
password = fake.password(length=12)
|
||||
|
||||
# Create account with password
|
||||
import uuid
|
||||
|
||||
unique_email = f"test_{uuid.uuid4().hex[:8]}@example.com"
|
||||
account = Account(
|
||||
email=fake.email(),
|
||||
email=unique_email,
|
||||
name=fake.name(),
|
||||
interface_language="en-US",
|
||||
status="active",
|
||||
@@ -322,9 +327,12 @@ class TestWebAppAuthService:
|
||||
"""
|
||||
# Arrange: Create account without password
|
||||
fake = Faker()
|
||||
import uuid
|
||||
|
||||
unique_email = f"test_{uuid.uuid4().hex[:8]}@example.com"
|
||||
|
||||
account = Account(
|
||||
email=fake.email(),
|
||||
email=unique_email,
|
||||
name=fake.name(),
|
||||
interface_language="en-US",
|
||||
status="active",
|
||||
@@ -431,9 +439,12 @@ class TestWebAppAuthService:
|
||||
"""
|
||||
# Arrange: Create banned account
|
||||
fake = Faker()
|
||||
import uuid
|
||||
|
||||
unique_email = f"test_{uuid.uuid4().hex[:8]}@example.com"
|
||||
|
||||
account = Account(
|
||||
email=fake.email(),
|
||||
email=unique_email,
|
||||
name=fake.name(),
|
||||
interface_language="en-US",
|
||||
status=AccountStatus.BANNED.value,
|
||||
|
8
api/uv.lock
generated
8
api/uv.lock
generated
@@ -1318,6 +1318,7 @@ dependencies = [
|
||||
{ name = "opentelemetry-semantic-conventions" },
|
||||
{ name = "opentelemetry-util-http" },
|
||||
{ name = "opik" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pandas", extra = ["excel", "output-formatting", "performance"] },
|
||||
{ name = "pandoc" },
|
||||
{ name = "psycogreen" },
|
||||
@@ -1469,7 +1470,7 @@ requires-dist = [
|
||||
{ name = "flask-login", specifier = "~=0.6.3" },
|
||||
{ name = "flask-migrate", specifier = "~=4.0.7" },
|
||||
{ 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 = "gevent", specifier = "~=24.11.1" },
|
||||
{ name = "gmpy2", specifier = "~=2.2.1" },
|
||||
@@ -1481,7 +1482,7 @@ requires-dist = [
|
||||
{ name = "googleapis-common-protos", specifier = "==1.63.0" },
|
||||
{ name = "gunicorn", specifier = "~=23.0.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 = "json-repair", specifier = ">=0.41.1" },
|
||||
{ name = "langfuse", specifier = "~=2.51.3" },
|
||||
@@ -1509,6 +1510,7 @@ requires-dist = [
|
||||
{ name = "opentelemetry-semantic-conventions", specifier = "==0.48b0" },
|
||||
{ name = "opentelemetry-util-http", specifier = "==0.48b0" },
|
||||
{ name = "opik", specifier = "~=1.7.25" },
|
||||
{ name = "packaging", specifier = "~=23.2" },
|
||||
{ name = "pandas", extras = ["excel", "output-formatting", "performance"], specifier = "~=2.2.2" },
|
||||
{ name = "pandoc", specifier = "~=2.4" },
|
||||
{ name = "psycogreen", specifier = "~=1.0.2" },
|
||||
@@ -1528,7 +1530,7 @@ requires-dist = [
|
||||
{ name = "sendgrid", specifier = "~=6.12.3" },
|
||||
{ name = "sentry-sdk", extras = ["flask"], specifier = "~=2.28.0" },
|
||||
{ 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 = "tiktoken", specifier = "~=0.9.0" },
|
||||
{ name = "transformers", specifier = "~=4.53.0" },
|
||||
|
Reference in New Issue
Block a user