diff --git a/.github/workflows/reusable-release-skill.yaml b/.github/workflows/reusable-release-skill.yaml index bbcd135..a231394 100644 --- a/.github/workflows/reusable-release-skill.yaml +++ b/.github/workflows/reusable-release-skill.yaml @@ -58,17 +58,16 @@ jobs: python -c "import os,base64,pathlib,subprocess; p=pathlib.Path('/tmp/pyarmor-reg.zip'); p.write_bytes(base64.standard_b64decode(os.environ['PYARMOR_REG_B64'])); subprocess.run(['pyarmor','reg',str(p)],check=True); p.unlink(missing_ok=True)" fi - # One script per pyarmor invocation (matches common desktop usage). + # 递归加密整个 scripts/(含 cli、service、db、util 等子包);仅 scripts/*.py 会漏模块导致运行时 ModuleNotFoundError。 - name: Encrypt Source Code run: | mkdir -p dist/package set -euo pipefail - for f in scripts/*.py; do - if [ -f "$f" ]; then - pyarmor gen --platform "${PYARMOR_PLATFORM}" -O dist/package "$f" - fi - done + test -d scripts + ( cd scripts && pyarmor gen --platform "${PYARMOR_PLATFORM}" -r -O ../dist/package . ) cp SKILL.md dist/package/ + if [ -d references ]; then cp -r references dist/package/; fi + if [ -d assets ]; then cp -r assets dist/package/; fi - name: Parse Metadata and Pack id: build_task diff --git a/tools/release.ps1 b/tools/release.ps1 index 9a3aa41..d0bb806 100644 --- a/tools/release.ps1 +++ b/tools/release.ps1 @@ -24,6 +24,10 @@ .NOTES Requires: git, PowerShell 5+ + + 加密与 ZIP 内容由 CI 工作流 reusable-release-skill.yaml 的「Encrypt Source Code」步骤执行: + 对 scripts/ 递归 PyArmor(-r),并复制 SKILL.md、references/、assets/(若存在)。 + 本脚本在打 tag 前会做一次 scripts/ 结构自检,避免子目录未提交却仍发布。 #> [CmdletBinding()] @@ -113,6 +117,42 @@ function Get-NextTag { } +function Assert-SkillReleasePackagingSources { + param([Parameter(Mandatory = $true)][string]$SkillRoot) + + $scriptsDir = Join-Path $SkillRoot "scripts" + $mainPy = Join-Path $scriptsDir "main.py" + if (-not (Test-Path -LiteralPath $mainPy)) { + return + } + + $text = Get-Content -LiteralPath $mainPy -Raw -Encoding UTF8 -ErrorAction SilentlyContinue + if ([string]::IsNullOrWhiteSpace($text)) { + return + } + + $need = @() + if ($text -match '(?m)^\s*from\s+cli\.') { $need += 'cli' } + if ($text -match '(?m)^\s*import\s+cli\b') { $need += 'cli' } + if ($text -match '(?m)^\s*from\s+service\.') { $need += 'service' } + if ($text -match '(?m)^\s*import\s+service\b') { $need += 'service' } + if ($text -match '(?m)^\s*from\s+db\.') { $need += 'db' } + if ($text -match '(?m)^\s*import\s+db\b') { $need += 'db' } + if ($text -match '(?m)^\s*from\s+util\.') { $need += 'util' } + if ($text -match '(?m)^\s*import\s+util\b') { $need += 'util' } + + foreach ($p in ($need | Select-Object -Unique)) { + $folder = Join-Path $scriptsDir $p + if (-not (Test-Path -LiteralPath $folder)) { + throw "Release check failed: scripts/main.py imports from '$p' but folder is missing: $folder" + } + } + + $pyFiles = @(Get-ChildItem -LiteralPath $scriptsDir -Filter *.py -Recurse -File -ErrorAction SilentlyContinue) + Write-Host "Packaging check: $($pyFiles.Count) Python file(s) under scripts/ (CI will obfuscate all recursively)." -ForegroundColor DarkGray +} + + function Ensure-CleanOrAutoCommit { param( [switch]$DoAutoCommit, @@ -171,6 +211,11 @@ try { Ensure-CleanOrAutoCommit -DoAutoCommit:$AutoCommit -NeedClean:$RequireClean -IsDryRun:$DryRun -Msg $CommitMessage + $skillRoot = (Get-GitOutput "rev-parse --show-toplevel" | Select-Object -First 1).Trim() + if (Test-Path -LiteralPath (Join-Path $skillRoot "SKILL.md")) { + Assert-SkillReleasePackagingSources -SkillRoot $skillRoot + } + $upstream = (& git rev-parse --abbrev-ref --symbolic-full-name "@{u}" 2>$null) $hasUpstream = ($LASTEXITCODE -eq 0)