refactor(resource): 统一资源管理、下载队列与多源回退 #1736
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| pull_request: | |
| types: [opened, synchronize, reopened, labeled] | |
| workflow_dispatch: | |
| inputs: | |
| create_release: | |
| description: 'Create Release' | |
| required: true | |
| default: false | |
| type: boolean | |
| concurrency: | |
| group: build-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| env: | |
| CREATE_RELEASE: ${{ (github.event_name == 'workflow_dispatch' && inputs.create_release == true) || startsWith(github.ref, 'refs/tags/') }} | |
| jobs: | |
| version: | |
| if: ${{ github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'build') }} | |
| runs-on: windows-latest | |
| outputs: | |
| version: ${{ steps.get_version.outputs.version }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Get version | |
| id: get_version | |
| shell: pwsh | |
| run: python tools/ci/get_version.py | |
| build: | |
| if: ${{ github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'build') }} | |
| runs-on: windows-latest | |
| needs: version | |
| outputs: | |
| unsigned_artifact_id: ${{ steps.upload-unsigned-artifact.outputs.artifact-id }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install uv | |
| shell: pwsh | |
| run: | | |
| Invoke-WebRequest -Uri https://astral.sh/uv/install.ps1 | Invoke-Expression | |
| - name: Create and activate virtual environment | |
| shell: pwsh | |
| run: | | |
| uv venv .venv --python=3.11.12 | |
| - name: Install dependencies | |
| shell: pwsh | |
| run: | | |
| .\.venv\Scripts\Activate.ps1 | |
| uv sync --group dev | |
| - name: Download and extract UPX into venv Scripts | |
| shell: pwsh | |
| run: | | |
| $venvScripts = ".\.venv\Scripts" | |
| $upxDir = Join-Path $venvScripts "upx" | |
| $sourceUpxPath = Join-Path $upxDir "upx-4.2.3-win64" "upx.exe" | |
| $destinationUpxPath = Join-Path $venvScripts "upx.exe" | |
| $zipPath = "upx.zip" | |
| Invoke-WebRequest -Uri "https://github.com/upx/upx/releases/download/v4.2.3/upx-4.2.3-win64.zip" -OutFile $zipPath | |
| Expand-Archive -Path $zipPath -DestinationPath $upxDir -Force | |
| Move-Item -Path $sourceUpxPath -Destination $destinationUpxPath -Force | |
| Remove-Item -Path $upxDir -Recurse -Force | |
| Remove-Item -Path $zipPath -Force | |
| - name: Build executables | |
| shell: pwsh | |
| env: | |
| RELEASE_VERSION: ${{ needs.version.outputs.version }} | |
| run: | | |
| echo "__version__ = '$env:RELEASE_VERSION'" | Out-File -FilePath src/one_dragon/version.py -Encoding utf8 | |
| .\.venv\Scripts\Activate.ps1 | |
| cd deploy | |
| uv run pyinstaller --noconfirm --clean "OneDragon-Installer.spec" | |
| uv run pyinstaller --noconfirm --clean "OneDragon-Launcher.spec" | |
| uv run pyinstaller --noconfirm --clean "OneDragon-RuntimeLauncher.spec" | |
| Copy-Item -Path "..\src" -Destination "dist\OneDragon-RuntimeLauncher\src" -Recurse -Force | |
| - name: Bundle dependencies into wheels | |
| shell: pwsh | |
| run: | | |
| # 激活虚拟环境 | |
| .\.venv\Scripts\Activate.ps1 | |
| # 创建目标目录并生成 wheel 包 | |
| New-Item -ItemType Directory -Path deploy/dist/wheels -Force | |
| uv export --no-hashes --no-dev --format requirements-txt > deploy/dist/requirements.txt | |
| pip wheel --wheel-dir=deploy/dist/wheels -r deploy/dist/requirements.txt | |
| # 压缩生成的 wheels 目录 | |
| Compress-Archive -Path deploy/dist/wheels/* -DestinationPath deploy/dist/ZenlessZoneZero-OneDragon-Environment.zip | |
| - name: Upload Installer | |
| if: ${{ env.CREATE_RELEASE == 'false' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: Installer | |
| path: deploy/dist/OneDragon-Installer.exe | |
| - name: Upload Launcher | |
| if: ${{ env.CREATE_RELEASE == 'false' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: Launcher | |
| path: deploy/dist/OneDragon-Launcher.exe | |
| - name: Upload RuntimeLauncher | |
| if: ${{ env.CREATE_RELEASE == 'false' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: RuntimeLauncher | |
| include-hidden-files: true | |
| path: deploy/dist/OneDragon-RuntimeLauncher/ | |
| - name: Upload Wheels | |
| if: ${{ env.CREATE_RELEASE == 'false' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: Wheels | |
| path: deploy/dist/ZenlessZoneZero-OneDragon-Environment.zip | |
| - name: Upload Dist | |
| if: ${{ env.CREATE_RELEASE == 'true' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: dist | |
| include-hidden-files: true | |
| if-no-files-found: error | |
| path: deploy/dist | |
| - name: Upload Unsigned Artifact | |
| if: ${{ env.CREATE_RELEASE == 'true' }} | |
| id: upload-unsigned-artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| # 上传后是 unsigned.zip | |
| name: unsigned | |
| if-no-files-found: error | |
| path: | | |
| .\deploy\dist\OneDragon-Launcher.exe | |
| .\deploy\dist\OneDragon-RuntimeLauncher\OneDragon-RuntimeLauncher.exe | |
| .\deploy\dist\OneDragon-Installer.exe | |
| sign: | |
| runs-on: windows-latest | |
| needs: | |
| - version | |
| - build | |
| if: ${{ github.repository_owner == 'OneDragon-Anything' && | |
| ((github.event_name == 'workflow_dispatch' && inputs.create_release == true) || startsWith(github.ref, 'refs/tags/')) | |
| }} | |
| env: | |
| SIGNED_DIR: 'signed' | |
| SIGNPATH_SIGNING_POLICY_SLUG: 'release-signing' | |
| steps: | |
| - name: Sign Artifact | |
| if: ${{ needs.build.outputs.unsigned_artifact_id != '' }} | |
| uses: signpath/github-action-submit-signing-request@v1.1 | |
| with: | |
| api-token: '${{ secrets.SIGNPATH_API_TOKEN }}' | |
| organization-id: '${{ vars.SIGNPATH_ORGANIZATION_ID }}' | |
| project-slug: 'ZenlessZoneZero-OneDragon' | |
| signing-policy-slug: '${{ env.SIGNPATH_SIGNING_POLICY_SLUG }}' | |
| github-artifact-id: "${{ needs.build.outputs.unsigned_artifact_id }}" | |
| wait-for-completion: true | |
| # 签名后会自动下载到这个目录并解压 文件名和原来的一样 | |
| output-artifact-directory: '${{ env.SIGNED_DIR }}' | |
| - name: Upload signed executables | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: signed | |
| if-no-files-found: error | |
| path: ${{ env.SIGNED_DIR }} | |
| release: | |
| runs-on: windows-latest | |
| needs: | |
| - version | |
| - build | |
| - sign | |
| if: ${{ always() && | |
| needs.build.result == 'success' && | |
| ((github.event_name == 'workflow_dispatch' && inputs.create_release == true) || startsWith(github.ref, 'refs/tags/')) && | |
| (needs.sign.result == 'success') | |
| }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Download dist | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dist | |
| path: deploy/dist | |
| - name: Download signed executables | |
| if: ${{ needs.sign.result == 'success' }} | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: signed | |
| path: deploy/dist/signed | |
| - name: Prepare release directory and models | |
| shell: pwsh | |
| env: | |
| RELEASE_VERSION: ${{ needs.version.outputs.version }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: python tools/ci/prepare_release_assets.py --release-version "$env:RELEASE_VERSION" | |
| - name: Create Release | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| tag_name: ${{ needs.version.outputs.version }} | |
| name: "Release ${{ needs.version.outputs.version }}" | |
| body: | | |
| ## 安装方式 | |
| - `ZenlessZoneZero-OneDragon-${{ needs.version.outputs.version }}-Full-Environment.zip` 为带环境的完整包,不需要额外下载资源。 | |
| - `ZenlessZoneZero-OneDragon-${{ needs.version.outputs.version }}-Full.zip` 为完整包,解压后选择解压目录为安装目录,只需要下载环境依赖。 | |
| - `ZenlessZoneZero-OneDragon-${{ needs.version.outputs.version }}-Installer.exe` 为精简安装程序,运行后会自动下载所需的资源。 | |
| - `ZenlessZoneZero-OneDragon-${{ needs.version.outputs.version }}-WithRuntime-Full.zip` 为内嵌运行时 + 源码 + 模型的完整独立包(无需安装 Python,也无需额外下载模型),解压即用。 | |
| - `ZenlessZoneZero-OneDragon-${{ needs.version.outputs.version }}-WithRuntime.zip` 为内嵌运行时 + 源码的精简独立包(无需安装 Python,模型按需下载),解压即用。 | |
| - 如果你想更新启动器,前往主程序【设置】-【资源下载】页面更新,或者下载 `ZenlessZoneZero-OneDragon-Launcher.zip`,解压后替换。 | |
| - `ZenlessZoneZero-OneDragon-RuntimeLauncher.zip` 为集成启动器更新包(exe + .runtime),用于已有环境的就地升级。 | |
| - __不要下载Source Code__ | |
| 安装前请查看 [安装指南](https://one-dragon.com/zzz/zh/quickstart.html) | |
| 若运行出错请查看 [自助排障指南](https://docs.qq.com/doc/p/7add96a4600d363b75d2df83bb2635a7c6a969b5) | |
| 已有 Mirror酱 CDK?前往 [Mirror酱](https://mirrorchyan.com/zh/projects?rid=ZZZ-OneDragon&source=zzzgh-release) 高速下载 | |
| ## 签名策略 (Code Signing Policy) | |
| 免费代码签名由 [SignPath.io](https://signpath.io/) 提供,证书由 [SignPath Foundation](https://signpath.org/) 颁发 | |
| 审批人:[DoctorReid](https://github.com/DoctorReid) [ShadowLemoon](https://github.com/ShadowLemoon) | |
| Free code signing provided by [SignPath.io](https://signpath.io/), certificate by [SignPath Foundation](https://signpath.org/) | |
| Approvers: [DoctorReid](https://github.com/DoctorReid) [ShadowLemoon](https://github.com/ShadowLemoon) | |
| ## 隐私政策 (Privacy Policy) | |
| 本程序的隐私政策详见:[隐私政策](.github/PRIVACY.md)。 | |
| See the [Privacy Policy](.github/PRIVACY.md). | |
| files: | | |
| ZenlessZoneZero-OneDragon-${{ needs.version.outputs.version }}-Full-Environment.zip | |
| ZenlessZoneZero-OneDragon-${{ needs.version.outputs.version }}-Full.zip | |
| ZenlessZoneZero-OneDragon-${{ needs.version.outputs.version }}-Installer.exe | |
| ZenlessZoneZero-OneDragon-${{ needs.version.outputs.version }}-WithRuntime-Full.zip | |
| ZenlessZoneZero-OneDragon-${{ needs.version.outputs.version }}-WithRuntime.zip | |
| ZenlessZoneZero-OneDragon-Environment.zip | |
| ZenlessZoneZero-OneDragon-Launcher.zip | |
| ZenlessZoneZero-OneDragon-RuntimeLauncher.zip | |
| generate_release_notes: false | |
| prerelease: ${{ contains(needs.version.outputs.version, '-beta.') }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Trigger CNB Release sync | |
| if: ${{ github.repository == 'OneDragon-Anything/ZenlessZoneZero-OneDragon' }} | |
| continue-on-error: true | |
| shell: pwsh | |
| env: | |
| CNB_TOKEN: ${{ secrets.CNB_TOKEN }} | |
| RELEASE_TAG: ${{ needs.version.outputs.version }} | |
| run: | | |
| if ([string]::IsNullOrWhiteSpace($env:CNB_TOKEN)) { | |
| throw 'Missing GitHub Actions secret: CNB_TOKEN' | |
| } | |
| $headers = @{ | |
| Accept = 'application/vnd.cnb.api+json' | |
| Authorization = "Bearer $env:CNB_TOKEN" | |
| } | |
| $body = @{ | |
| branch = 'main' | |
| event = 'api_trigger_release' | |
| title = "Sync GitHub Release $env:RELEASE_TAG" | |
| env = @{ | |
| RELEASE_TAG = $env:RELEASE_TAG | |
| } | |
| } | ConvertTo-Json -Depth 3 | |
| $response = Invoke-RestMethod ` | |
| -Uri 'https://api.cnb.cool/OneDragon-Anything/ZenlessZoneZero-OneDragon/-/build/start' ` | |
| -Method Post ` | |
| -Headers $headers ` | |
| -ContentType 'application/json' ` | |
| -TimeoutSec 60 ` | |
| -Body $body | |
| $response | ConvertTo-Json -Depth 5 | |
| if ($response.success -ne $true) { | |
| throw "CNB build trigger failed: $($response.message)" | |
| } |