fix(editor): align dual-pane comparison views #296
Workflow file for this run
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, Release, and Publish Updates | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| jobs: | |
| build-portable: | |
| runs-on: windows-latest | |
| name: Build ${{ matrix.package-label }} Portable Package | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - variant: cpu | |
| package-label: cpu | |
| source-ref: tag | |
| torch-index: https://download.pytorch.org/whl/cpu | |
| - variant: cuda13.0 | |
| package-label: cuda13.0 | |
| source-ref: tag | |
| torch-index: https://download.pytorch.org/whl/cu130 | |
| - variant: cuda12.6 | |
| package-label: cuda12.6 | |
| source-ref: tag | |
| torch-index: https://download.pytorch.org/whl/cu126 | |
| - variant: rocm7.2.1 | |
| package-label: rocm7.2.1 | |
| source-ref: tag | |
| torch-index: https://pypi.org/simple | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Prepare portable package from reference release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $sourceRef = '${{ matrix.source-ref }}' | |
| if ($sourceRef -eq 'tag') { $sourceRef = '${{ github.ref_name }}' } | |
| if ($sourceRef -ne '${{ github.ref_name }}') { | |
| & git fetch origin $sourceRef | |
| if ($LASTEXITCODE -ne 0) { throw "Failed to fetch source ref $sourceRef." } | |
| & git checkout --force -B $sourceRef "origin/$sourceRef" | |
| if ($LASTEXITCODE -ne 0) { throw "Failed to check out source ref $sourceRef." } | |
| } | |
| $archive = Join-Path $env:RUNNER_TEMP 'manga-translator-ui-portable.7z' | |
| $extractDir = Join-Path $env:GITHUB_WORKSPACE 'portable' | |
| gh release download portable --repo hgmzhn/manga-translator-ui --pattern manga-translator-ui-portable.7z --output $archive --clobber | |
| if ($LASTEXITCODE -ne 0) { throw 'Failed to download the portable reference package.' } | |
| Remove-Item $extractDir -Recurse -Force -ErrorAction SilentlyContinue | |
| 7z x $archive "-o$extractDir" -y | |
| if ($LASTEXITCODE -ne 0) { throw 'Failed to extract the portable reference package.' } | |
| Remove-Item $archive -Force | |
| $pythonCandidates = @( | |
| Get-ChildItem -LiteralPath $extractDir -Filter python.exe -File -Recurse | | |
| Where-Object { $_.FullName -match '[\\/]packaging[\\/]python[\\/]python\.exe$' } | |
| ) | |
| if ($pythonCandidates.Count -ne 1) { | |
| throw "Expected exactly one portable Python, found $($pythonCandidates.Count)." | |
| } | |
| $portableDir = $pythonCandidates[0].Directory.Parent.Parent.FullName | |
| if (-not (Test-Path (Join-Path $portableDir 'Win-Start.bat'))) { | |
| throw "Portable root was not found next to $($pythonCandidates[0].FullName)." | |
| } | |
| $excluded = @('.git', '.github', '.venv', '.venv_cpu', '.venv_gpu', 'build', 'dist', 'models', 'models_backup', 'result', 'logs', 'scripts', 'test', 'reference-code', 'PortableGit', 'uploads', 'upload-cache', 'originals', 'manga_translator_work', 'memory_profiles', '.idea', '.vscode') | |
| Get-ChildItem -LiteralPath $env:GITHUB_WORKSPACE -Force | | |
| Where-Object { $_.Name -notin $excluded -and $_.Name -ne 'portable' } | | |
| ForEach-Object { Copy-Item -LiteralPath $_.FullName -Destination $portableDir -Recurse -Force } | |
| Remove-Item (Join-Path $portableDir '.git') -Recurse -Force -ErrorAction SilentlyContinue | |
| Copy-Item -LiteralPath (Join-Path $env:GITHUB_WORKSPACE '.git') -Destination (Join-Path $portableDir '.git') -Recurse -Force | |
| if (-not (Test-Path (Join-Path $portableDir 'packaging\python\python.exe'))) { throw 'Portable Python was not found in the reference package.' } | |
| if (-not (Test-Path (Join-Path $portableDir 'packaging\uv.exe'))) { throw 'Portable uv was not found in the reference package.' } | |
| Set-Content -LiteralPath (Join-Path $portableDir 'VERSION') -Value ('${{ github.ref_name }}' -replace '^v', '') -Encoding utf8 | |
| Set-Content -LiteralPath (Join-Path $portableDir 'packaging\VERSION') -Value ('${{ github.ref_name }}' -replace '^v', '') -Encoding utf8 | |
| "PORTABLE_DIR=$portableDir" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 | |
| - name: Install ${{ matrix.variant }} dependencies into bundled Python | |
| if: ${{ matrix.variant != 'rocm7.2.1' }} | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $uv = Join-Path $env:PORTABLE_DIR 'packaging\uv.exe' | |
| $python = Join-Path $env:PORTABLE_DIR 'packaging\python\python.exe' | |
| $requirements = Join-Path $env:RUNNER_TEMP 'requirements-portable-${{ matrix.package-label }}.txt' | |
| try { | |
| & $uv export --locked --no-hashes --no-default-groups --group '${{ matrix.variant }}' --format requirements.txt --output-file $requirements | |
| if ($LASTEXITCODE -ne 0) { throw 'Failed to export locked dependencies.' } | |
| & $uv pip install --python $python --index '${{ matrix.torch-index }}' --index-strategy unsafe-best-match --requirement $requirements | |
| if ($LASTEXITCODE -ne 0) { throw 'Failed to install dependencies into bundled Python.' } | |
| } finally { | |
| Remove-Item $requirements -Force -ErrorAction SilentlyContinue | |
| } | |
| - name: Install ROCm 7.2.1 base dependencies into bundled Python | |
| if: ${{ matrix.variant == 'rocm7.2.1' }} | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $uv = Join-Path $env:PORTABLE_DIR 'packaging\uv.exe' | |
| $python = Join-Path $env:PORTABLE_DIR 'packaging\python\python.exe' | |
| $requirements = Join-Path $env:RUNNER_TEMP 'requirements-portable-rocm7.2.1.txt' | |
| try { | |
| & $uv export --locked --no-hashes --no-default-groups --group rocm7.2.1 --no-emit-package torch --no-emit-package torchvision --format requirements.txt --output-file $requirements | |
| if ($LASTEXITCODE -ne 0) { throw 'Failed to export locked ROCm 7.2.1 base dependencies.' } | |
| & $uv pip install --python $python --no-deps --requirement $requirements | |
| if ($LASTEXITCODE -ne 0) { throw 'Failed to install ROCm 7.2.1 base dependencies into bundled Python.' } | |
| } finally { | |
| Remove-Item $requirements -Force -ErrorAction SilentlyContinue | |
| } | |
| - name: Install Windows ROCm 7.2.1 runtime | |
| if: ${{ matrix.variant == 'rocm7.2.1' }} | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $python = Join-Path $env:PORTABLE_DIR 'packaging\python\python.exe' | |
| & $python -m pip uninstall torch torchvision torchaudio -y | |
| if ($LASTEXITCODE -ne 0) { throw 'Failed to remove the non-ROCm PyTorch runtime.' } | |
| & $python -m pip install --no-cache-dir ` | |
| 'https://repo.radeon.com/rocm/windows/rocm-rel-7.2.1/rocm_sdk_core-7.2.1-py3-none-win_amd64.whl' ` | |
| 'https://repo.radeon.com/rocm/windows/rocm-rel-7.2.1/rocm_sdk_devel-7.2.1-py3-none-win_amd64.whl' ` | |
| 'https://repo.radeon.com/rocm/windows/rocm-rel-7.2.1/rocm_sdk_libraries_custom-7.2.1-py3-none-win_amd64.whl' ` | |
| 'https://repo.radeon.com/rocm/windows/rocm-rel-7.2.1/rocm-7.2.1.tar.gz' | |
| if ($LASTEXITCODE -ne 0) { throw 'Failed to install the ROCm 7.2.1 SDK.' } | |
| & $python -m pip install --no-cache-dir ` | |
| 'https://repo.radeon.com/rocm/windows/rocm-rel-7.2.1/torch-2.9.1%2Brocm7.2.1-cp312-cp312-win_amd64.whl' ` | |
| 'https://repo.radeon.com/rocm/windows/rocm-rel-7.2.1/torchaudio-2.9.1%2Brocm7.2.1-cp312-cp312-win_amd64.whl' ` | |
| 'https://repo.radeon.com/rocm/windows/rocm-rel-7.2.1/torchvision-0.24.1%2Brocm7.2.1-cp312-cp312-win_amd64.whl' | |
| if ($LASTEXITCODE -ne 0) { throw 'Failed to install the ROCm 7.2.1 PyTorch runtime.' } | |
| - name: Clean dependency caches | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $uv = Join-Path $env:PORTABLE_DIR 'packaging\uv.exe' | |
| $python = Join-Path $env:PORTABLE_DIR 'packaging\python\python.exe' | |
| & $uv cache clean | |
| if ($LASTEXITCODE -ne 0) { throw 'Failed to clean the uv cache.' } | |
| & $python -m pip cache purge | |
| if ($LASTEXITCODE -ne 0) { throw 'Failed to clean the pip cache.' } | |
| - name: Install model files into portable package | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $modelArchive = Join-Path $env:RUNNER_TEMP 'models.7z' | |
| $portableDir = $env:PORTABLE_DIR | |
| try { | |
| gh release download v1.7.9 --repo hgmzhn/manga-translator-ui --pattern models.7z --output $modelArchive --clobber | |
| if ($LASTEXITCODE -ne 0) { throw 'Failed to download model files.' } | |
| Remove-Item (Join-Path $portableDir 'models') -Recurse -Force -ErrorAction SilentlyContinue | |
| 7z x $modelArchive "-o$portableDir" -y | |
| if ($LASTEXITCODE -ne 0) { throw 'Failed to extract model files.' } | |
| if (-not (Test-Path (Join-Path $portableDir 'models'))) { throw 'The model archive did not contain a models directory.' } | |
| } finally { | |
| Remove-Item $modelArchive -Force -ErrorAction SilentlyContinue | |
| } | |
| - name: Smoke test bundled runtime | |
| if: ${{ matrix.variant != 'rocm7.2.1' }} | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $python = Join-Path $env:PORTABLE_DIR 'packaging\python\python.exe' | |
| # PyQt6 must load last; its Qt DLL paths can break torch/onnxruntime resolution on Windows. | |
| & $python -c "import torch, onnxruntime, PyQt6; print(torch.__version__, onnxruntime.__version__)" | |
| if ($LASTEXITCODE -ne 0) { throw 'Bundled runtime import smoke test failed.' } | |
| - name: Smoke test ROCm 7.2.1 bundled runtime metadata | |
| if: ${{ matrix.variant == 'rocm7.2.1' }} | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $python = Join-Path $env:PORTABLE_DIR 'packaging\python\python.exe' | |
| # PyQt6 must load last; its Qt DLL paths can break onnxruntime resolution on Windows. | |
| & $python -c "from importlib.metadata import version; import onnxruntime, PyQt6; v = version('torch'); assert 'rocm7.2.1' in v, v; print(v, onnxruntime.__version__)" | |
| if ($LASTEXITCODE -ne 0) { throw 'ROCm 7.2.1 bundled runtime metadata smoke test failed.' } | |
| - name: Archive ${{ matrix.package-label }} portable package | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $releaseDir = Join-Path $env:GITHUB_WORKSPACE 'release' | |
| New-Item -ItemType Directory -Path $releaseDir -Force | Out-Null | |
| Push-Location $env:PORTABLE_DIR | |
| 7z a -v1990m -m0=lzma2 -ms=on (Join-Path $releaseDir 'manga-translator-${{ matrix.package-label }}-${{ github.ref_name }}.7z') . | |
| $archiveExitCode = $LASTEXITCODE | |
| Pop-Location | |
| if ($archiveExitCode -ne 0) { throw 'Failed to archive the portable package.' } | |
| - name: Upload ${{ matrix.package-label }} portable archive | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: manga-translator-${{ matrix.package-label }}-portable | |
| path: release/*.7z.* | |
| release-and-publish: | |
| needs: [build-portable] | |
| runs-on: ubuntu-latest | |
| name: Create Release and Publish Updates | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Download portable archives | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: release_assets | |
| merge-multiple: true | |
| - name: Read CHANGELOG | |
| id: changelog | |
| run: | | |
| set -Eeuo pipefail | |
| VERSION=$(echo "${{ github.ref_name }}" | sed 's/^v//') | |
| CHANGELOG_FILE="doc/CHANGELOG_v${VERSION}.md" | |
| if [ -f "$CHANGELOG_FILE" ]; then | |
| DELIM="END_OF_CHANGELOG_${GITHUB_RUN_ID}_${RANDOM}" | |
| { | |
| printf 'changelog<<%s\n' "$DELIM" | |
| sed -e '$a\' "$CHANGELOG_FILE" | |
| printf '%s\n' "$DELIM" | |
| } >> "$GITHUB_OUTPUT" | |
| else | |
| printf 'changelog=%s\n' "未找到更新日志文件" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Delete existing GitHub Release for this version | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| if [[ ! "$GITHUB_REF_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([.-].*)?$ ]]; then | |
| echo "Not a semantic version tag: $GITHUB_REF_NAME; skip old release deletion." | |
| exit 0 | |
| fi | |
| if gh release view "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then | |
| echo "Deleting existing release $GITHUB_REF_NAME before publishing..." | |
| gh release delete "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" --yes | |
| else | |
| echo "No existing release for $GITHUB_REF_NAME." | |
| fi | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| tag_name: ${{ github.ref_name }} | |
| name: Release ${{ github.ref_name }} | |
| body: ${{ steps.changelog.outputs.changelog }} | |
| files: release_assets/* | |
| draft: false | |
| prerelease: false |