Skip to content

fix: 更新验证脚本,添加 'skills' 目录到排除列表 #137

fix: 更新验证脚本,添加 'skills' 目录到排除列表

fix: 更新验证脚本,添加 'skills' 目录到排除列表 #137

Workflow file for this run

name: CI - Strict Validator
on:
push:
branches: [ "master" ]
paths-ignore:
- 'public/**'
pull_request:
branches: [ "master" ]
jobs:
validate:
name: Validate Standards
runs-on: ubuntu-latest
steps:
- name: Checkout Source
uses: actions/checkout@v4
- name: Set up Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "latest"
- name: Run Validation Script
run: |
python3 -c "
import os
import json
import sys
import subprocess
# ==========================================
# 配置区域
# ==========================================
# case.json 通用必须字段
REQUIRED_FIELDS = {
'name': '模版名称 (name)',
'user': '作者 (user)',
'version': '版本号 (version)',
'description': '描述信息 (description)',
'description_en': '英文描述 (description_en)',
'tags': '标签 (tags)'
}
# 按模板类型的额外必须字段
TYPE_REQUIRED_FIELDS = {
'preset': {
'arch': '架构 (arch, e.g. x86_64/arm64)',
},
'base': {
'arch': '架构 (arch)',
'provider': '云厂商 (provider)',
},
'userdata': {
'nameZh': '中文名称 (nameZh)',
'type': '脚本类型 (type, e.g. bash/powershell)',
'category': '分类 (category, e.g. basic/tool/service/security)',
},
'compose': {},
}
repo_root = '.'
exclude_dirs = {'.git', '.github', 'public', 'previous_build', '__pycache__', 'plugins', 'skills', 'assets'}
# ==========================================
# 主校验逻辑
# ==========================================
has_error = False
print('🔍 Starting Strict Validation...')
print(f'ℹ️ Enforcing required fields: {list(REQUIRED_FIELDS.keys())}')
print(f'ℹ️ Terraform check: Syntax ONLY (Ignoring indentation)')
print('=' * 60)
for provider in sorted(os.listdir(repo_root)):
provider_path = os.path.join(repo_root, provider)
if not os.path.isdir(provider_path) or provider in exclude_dirs:
continue
for template in sorted(os.listdir(provider_path)):
template_path = os.path.join(provider_path, template)
if not os.path.isdir(template_path): continue
template_id = f'{provider}/{template}'
current_files = set(os.listdir(template_path))
# -------------------------------------------------
# Check 1: README.md & README_EN.md
# -------------------------------------------------
if 'README.md' not in current_files:
lower_files = [f.lower() for f in current_files]
if 'readme.md' in lower_files:
print(f'❌ [FILE] {template_id}: Found lowercase readme.md. MUST be CAPS: README.md')
else:
print(f'❌ [FILE] {template_id}: Missing required file: README.md')
has_error = True
if 'README_EN.md' not in current_files:
print(f'❌ [FILE] {template_id}: Missing required file: README_EN.md')
has_error = True
# -------------------------------------------------
# Check 2: case.json
# -------------------------------------------------
case_path = os.path.join(template_path, 'case.json')
if 'case.json' not in current_files:
print(f'❌ [FILE] {template_id}: Missing required file: case.json')
has_error = True
else:
try:
with open(case_path, 'r', encoding='utf-8') as f:
data = json.load(f)
# 字段缺失检查 (通用)
missing = [k for k in REQUIRED_FIELDS if k not in data]
# 字段缺失检查 (按模板类型)
tmpl_type = data.get('template', 'preset') or 'preset'
extra_required = TYPE_REQUIRED_FIELDS.get(tmpl_type, {})
missing_extra = [k for k in extra_required if k not in data]
all_missing = missing + missing_extra
if all_missing:
if 'description' in all_missing and 'DESCRIPTION' in data:
print(f'❌ [JSON] {template_id}: Found legacy key \"DESCRIPTION\". Please rename to lowercase \"description\"')
else:
all_required = {**REQUIRED_FIELDS, **extra_required}
desc_list = [all_required[k] for k in all_missing]
print(f'❌ [JSON] {template_id} (type={tmpl_type}): Missing required fields: {desc_list}')
has_error = True
else:
# 字段内容检查
if not data['name'] or str(data['name']).strip() == '':
print(f'❌ [JSON] {template_id}: Field \"name\" cannot be empty')
has_error = True
if not data['user'] or str(data['user']).strip() == '':
print(f'❌ [JSON] {template_id}: Field \"user\" cannot be empty')
has_error = True
if not data['description'] or str(data['description']).strip() == '':
print(f'❌ [JSON] {template_id}: Field \"description\" cannot be empty')
has_error = True
ver = data['version']
if not isinstance(ver, str):
print(f'❌ [JSON] {template_id}: \"version\" must be a STRING (e.g. \"1.0.1\"), found type: {type(ver).__name__}')
has_error = True
elif ver.strip() == '':
print(f'❌ [JSON] {template_id}: Field \"version\" cannot be empty')
has_error = True
if not data['description_en'] or str(data['description_en']).strip() == '':
print(f'❌ [JSON] {template_id}: Field \"description_en\" cannot be empty')
has_error = True
tags = data['tags']
if not isinstance(tags, list) or len(tags) == 0:
print(f'❌ [JSON] {template_id}: Field \"tags\" must be a non-empty list')
has_error = True
except json.JSONDecodeError as e:
print(f'❌ [JSON] {template_id}: case.json is invalid JSON! Error: {e}')
has_error = True
# -------------------------------------------------
# Check 3: Terraform 语法检查 (忽略格式美观度)
# -------------------------------------------------
has_tf = any(f.endswith('.tf') for f in current_files)
if has_tf:
# 修改说明:
# -write=false: 不修改文件
# -recursive: 递归检查目录
# 移除了 -check: 这样只有在无法解析(语法错误)时才会返回非0状态码
result = subprocess.run(
['terraform', 'fmt', '-write=false', '-recursive', template_path],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
if result.returncode != 0:
# 只有语法严重错误导致无法解析时,这里才会报错
print(f'❌ [TF] {template_id}: Syntax Error (Code invalid).')
print(f' Error details: {result.stderr.strip()}')
has_error = True
print('=' * 60)
if has_error:
print('🚫 CHECK FAILED. Please fix the errors above.')
sys.exit(1)
else:
print('✅ ALL CHECKS PASSED. Ready to merge.')
sys.exit(0)
"