Files
Petrus Han d06ab44e52 Feature Architecture & CI Improvements (#4)
* chore: 升级 tj-actions/changed-files 到 v46.0.1

* Add feature-based architecture for version-specific config

Introduces a feature registry and auto-discovery system under modules/features/ to manage version-specific configuration logic. Adds base classes and decorators for feature registration, semantic version comparison, and applies features in global, infrastructure, plugins, and services modules. Implements features for trigger worker, plugin metrics, and external Prometheus (3.7.0+). Updates i18n translations and documentation to reflect the new architecture and configuration options. Includes tests for feature registration, version parsing, and applicability.

* Add Docker registry secret generator and secret utils

Added generate-image-repo-secret.sh for interactively creating Kubernetes imagePullSecret for private Docker registries. Updated .gitignore to better exclude sensitive files. Added utils/secrets.py for secret key generation. Updated README files with instructions for using the new secret generator script.

* ci: add unit tests and module validation

- Add test job to validate all Python module imports
- Add feature tests, services tests, and S3 config tests
- Add shell script validation with shellcheck
- Update actions to v4/v5 versions
- Add CI integration test plan documentation

* ci: skip interactive tests in CI environment

test_services.py and test_s3_config.py require interactive input,
skip them until --ci mode is implemented

* chore: add PR template

* feat: add --ci non-interactive mode for CI testing

- Add set_ci_mode() and is_ci_mode() to config.py
- Add --ci flag to generate-values-prd.py
- Update utils/prompts.py to return defaults in CI mode
- Update i18n/language.py to use English in CI mode
- Update utils/downloader.py to use latest version in CI mode
- Update version_manager.py to avoid variable shadowing
- Enable CI mode in test files for non-interactive testing
2026-02-04 15:19:36 +09:00

178 lines
6.4 KiB
Python

"""Version management for Dify EE"""
import sys
from typing import Dict, Any, Optional
import config
from utils import Colors, print_header, print_info, print_success, print_error, print_warning
from i18n import get_translator
_t = get_translator()
class VersionManager:
"""Version manager - manages Dify EE configuration modules for different versions"""
# Version configuration: defines modules supported by each version
# Uses major version format (3.x, 2.x) to avoid confusion with specific chart versions (e.g., 3.5.6)
VERSION_CONFIGS = {
"3.x": {
"name": "Dify Enterprise Edition 3.x",
"modules": [
"global",
"infrastructure",
"networking",
"mail",
"plugins", # Version 3.x supports plugin module
"services"
],
"description": "Full version with plugin support"
},
"2.x": {
"name": "Dify Enterprise Edition 2.x",
"modules": [
"global",
"infrastructure",
"networking",
"mail",
# Version 2.x does not support plugin module
"services"
],
"description": "Version without plugin support"
},
# More version configurations can be added here (e.g., "4.x")
}
@classmethod
def get_available_versions(cls) -> list:
"""Get list of available versions"""
return list(cls.VERSION_CONFIGS.keys())
@classmethod
def get_version_info(cls, version: str) -> Optional[Dict[str, Any]]:
"""Get version information"""
return cls.VERSION_CONFIGS.get(version)
@classmethod
def get_version_modules(cls, version: str) -> list:
"""Get list of modules supported by version"""
version_cfg = cls.get_version_info(version)
if version_cfg:
return version_cfg.get("modules", [])
return []
@classmethod
def is_module_supported(cls, version: str, module: str) -> bool:
"""Check if version supports a module"""
modules = cls.get_version_modules(version)
return module in modules
@classmethod
def prompt_version_selection(cls) -> str:
"""Interactive version selection. In CI mode, returns first (latest) version."""
versions = cls.get_available_versions()
# CI mode: return first version without prompting
if config.is_ci_mode():
first_version = versions[0] if versions else "3.x"
version_config = cls.get_version_info(first_version)
print_info(f"[CI] Using version: {version_config.get('name', first_version)}")
return first_version
print_header(_t('select_dify_version'))
print_info(_t('select_version_prompt'))
print()
version_options = []
for i, version in enumerate(versions, 1):
version_cfg = cls.get_version_info(version)
name = version_cfg.get("name", f"Version {version}")
desc = version_cfg.get("description", "")
modules = version_cfg.get("modules", [])
print(f" {i}. {name}")
print(f" {_t('version')}: {version}")
if desc:
print(f" {_t('description')}: {desc}")
print(f" {_t('supported_modules')}: {', '.join(modules)}")
print()
version_options.append(version)
while True:
try:
default_text = _t('default')
choice = input(f"{Colors.BOLD}{_t('select_version_range')} [1-{len(versions)}] ({default_text}: 1): {Colors.ENDC}").strip()
if not choice:
choice = "1"
idx = int(choice) - 1
if 0 <= idx < len(versions):
selected_version = version_options[idx]
version_cfg = cls.get_version_info(selected_version)
print_success(f"{_t('selected')}: {version_cfg.get('name', selected_version)}")
return selected_version
else:
range_text = _t('enter_number_range')
print_error(f"{_t('invalid_selection')} {range_text} 1-{len(versions)}")
except ValueError:
print_error(_t('enter_valid_number'))
except KeyboardInterrupt:
print("\n")
print_warning(_t('user_interrupted'))
sys.exit(0)
@classmethod
def detect_version_from_values(cls, values: Dict[str, Any]) -> Optional[str]:
"""Detect version from values.yaml if possible"""
# Try to detect version from Chart.yaml or other sources
# This can be implemented based on actual requirements
# For now, return None to let user manually select
return None
@classmethod
def map_chart_version_to_ee_version(cls, chart_version: Optional[str]) -> Optional[str]:
"""
Map Helm Chart version to Dify EE version
Mapping rules:
- Chart version 3.x.x -> Dify EE 3.x
- Chart version 2.x.x -> Dify EE 2.x
- Chart version 1.x.x -> Dify EE 2.x (legacy)
- Chart version 4.x.x -> Dify EE 4.x (future)
- Unknown or None -> None (requires manual selection)
Args:
chart_version: Helm Chart version string (e.g., "3.5.6", "3.6.0-beta.1")
Returns:
Dify EE version string (e.g., "3.x", "2.x") or None if cannot be determined
"""
if not chart_version:
return None
# Extract major version number
try:
# Handle versions like "3.5.6", "3.6.0-beta.1", etc.
major_version = int(chart_version.split('.')[0])
# Map major version to EE version (using x format for extensibility)
# Future versions (4.x, 5.x, etc.) will automatically map correctly
if major_version >= 4:
return f"{major_version}.x"
elif major_version >= 3:
return "3.x"
elif major_version >= 2:
return "2.x"
elif major_version >= 1:
# Chart version 1.x maps to EE 2.x (legacy support)
return "2.x"
else:
return None
except (ValueError, IndexError):
# If version format is unexpected, return None
return None