docs: Refine Windows troubleshooting tip wording #42
This file contains 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: Test and Release | |
on: | |
push: | |
branches: | |
- main | |
- master | |
permissions: | |
id-token: write | |
contents: write | |
pull-requests: write | |
env: | |
REGISTRY: ghcr.io | |
REPO_LOWER: ${{ github.repository_owner }}/${{ github.event.repository.name }} | |
GHCR_REPO: ghcr.io/${{ github.repository }} | |
DOCKERHUB_REPO: byaidu/pdf2zh | |
WIN_EXE_PYTHON_VERSION: "3.12.9" | |
jobs: | |
check-repository: | |
name: Check if running in main repository | |
runs-on: ubuntu-latest | |
outputs: | |
is_main_repo: ${{ github.repository == 'Byaidu/PDFMathTranslate' }} | |
steps: | |
- run: echo "Running repository check" | |
test: | |
needs: check-repository | |
uses: ./.github/workflows/python-test.yml | |
if: needs.check-repository.outputs.is_main_repo == 'true' | |
build: | |
name: Build distribution 📦 | |
needs: [test, check-repository] | |
if: needs.check-repository.outputs.is_main_repo == 'true' | |
runs-on: ubuntu-latest | |
outputs: | |
is_release: ${{ steps.check-version.outputs.tag }} | |
version: ${{ steps.check-version.outputs.tag && steps.get-release-version.outputs.version || steps.get-dev-version.outputs.version }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
persist-credentials: true | |
fetch-depth: 2 | |
token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Setup uv with Python 3.12 | |
uses: astral-sh/setup-uv@1edb52594c857e2b5b13128931090f0640537287 # v5.3.0 | |
with: | |
python-version: "3.12" | |
enable-cache: true | |
cache-dependency-glob: "pyproject.toml" | |
- name: Check if there is a parent commit | |
id: check-parent-commit | |
run: | | |
echo "sha=$(git rev-parse --verify --quiet HEAD^)" >> $GITHUB_OUTPUT | |
- name: Detect and tag new version | |
id: check-version | |
if: steps.check-parent-commit.outputs.sha | |
uses: salsify/action-detect-and-tag-new-version@b1778166f13188a9d478e2d1198f993011ba9864 # v2.0.3 | |
with: | |
version-command: | | |
cat pyproject.toml | grep "version = " | head -n 1 | awk -F'"' '{print $2}' | |
tag-template: 'awv{VERSION}' | |
- name: Install Dependencies | |
run: | | |
uv sync | |
- name: Bump version for developmental release | |
if: "!steps.check-version.outputs.tag" | |
id: get-dev-version | |
run: | | |
version=$(bumpver update --patch --tag=final --dry 2>&1 | grep "New Version" | awk '{print $NF}') | |
echo "version=$version.dev$(date +%s)" >> $GITHUB_OUTPUT | |
bumpver update --set-version $version.dev$(date +%s) | |
- name: Get release version | |
if: steps.check-version.outputs.tag | |
id: get-release-version | |
run: | | |
version=$(cat pyproject.toml | grep "version = " | head -n 1 | awk -F'"' '{print $2}') | |
echo "version=$version" >> $GITHUB_OUTPUT | |
- name: Build package | |
run: "uv build" | |
- name: Store the distribution packages | |
uses: actions/[email protected] | |
with: | |
name: python-package-distributions | |
path: dist/ | |
publish-to-pypi: | |
name: Publish Python 🐍 distribution 📦 to PyPI | |
if: needs.build.outputs.is_release != '' | |
needs: | |
- check-repository | |
- build | |
- test-win64-exe | |
runs-on: ubuntu-latest | |
environment: | |
name: pypi | |
url: https://pypi.org/p/pdf2zh | |
permissions: | |
id-token: write | |
steps: | |
- name: Download all the dists | |
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 | |
with: | |
name: python-package-distributions | |
path: dist/ | |
- name: Publish distribution 📦 to PyPI | |
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4 | |
publish-to-testpypi: | |
name: Publish Python 🐍 distribution 📦 to TestPyPI | |
if: needs.build.outputs.is_release == '' | |
needs: | |
- check-repository | |
- build | |
- test-win64-exe | |
runs-on: ubuntu-latest | |
environment: | |
name: testpypi | |
url: https://test.pypi.org/p/pdf2zh | |
permissions: | |
id-token: write | |
steps: | |
- name: Download all the dists | |
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 | |
with: | |
name: python-package-distributions | |
path: dist/ | |
- name: Publish distribution 📦 to TestPyPI | |
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4 | |
with: | |
repository-url: https://test.pypi.org/legacy/ | |
build-docker-image: | |
strategy: | |
fail-fast: false | |
matrix: | |
include: | |
- platform: linux/amd64 | |
runner: ubuntu-latest | |
- platform: linux/arm64 | |
runner: ubuntu-24.04-arm | |
runs-on: ${{ matrix.runner }} | |
needs: | |
- build | |
- check-repository | |
if: needs.check-repository.outputs.is_main_repo == 'true' | |
environment: | |
name: ${{ needs.build.outputs.is_release != '' && 'pypi' || 'testpypi' }} | |
url: ${{ needs.build.outputs.is_release != '' && 'https://hub.docker.com/r/byaidu/pdf2zh/tags?name=latest' || 'https://hub.docker.com/r/byaidu/pdf2zh/tags?name=dev' }} | |
permissions: | |
contents: read | |
packages: write | |
steps: | |
- name: Convert to lowercase | |
run: | | |
echo "GHCR_REPO_LOWER=$(echo ${{ env.GHCR_REPO }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV | |
- name: Prepare | |
run: | | |
platform=${{ matrix.platform }} | |
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV | |
- name: Checkout repository | |
uses: actions/checkout@v4 | |
- name: Setup uv with Python 3.12 | |
uses: astral-sh/setup-uv@1edb52594c857e2b5b13128931090f0640537287 # v5.3.0 | |
with: | |
python-version: "3.12" | |
enable-cache: true | |
cache-dependency-glob: "pyproject.toml" | |
- name: Set version from build job | |
if: needs.build.outputs.is_release == '' | |
run: | | |
uv tool install bumpver | |
echo "Using version: ${{ needs.build.outputs.version }}" | |
bumpver update --set-version ${{ needs.build.outputs.version }} | |
- name: Docker meta | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: | | |
${{ env.DOCKERHUB_REPO }} | |
${{ env.GHCR_REPO_LOWER }} | |
tags: | | |
type=raw,value=dev | |
type=raw,value=${{ needs.build.outputs.version }},enable=${{ needs.build.outputs.is_release != '' }} | |
type=raw,value=latest,enable=${{ needs.build.outputs.is_release != '' }} | |
- name: Login to Docker.io | |
uses: docker/login-action@v3 | |
with: | |
registry: docker.io | |
username: ${{ secrets.DOCKER_USERNAME }} | |
password: ${{ secrets.DOCKER_PASSWORD }} | |
- name: Login to GHCR | |
uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.repository_owner }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Build and push by digest | |
id: build | |
uses: docker/build-push-action@v6 | |
with: | |
platforms: ${{ matrix.platform }} | |
labels: ${{ steps.meta.outputs.labels }} | |
outputs: type=image,"name=${{ env.DOCKERHUB_REPO }},${{ env.GHCR_REPO_LOWER }}",push-by-digest=true,name-canonical=true,push=true | |
cache-from: ${{ matrix.platform == 'linux/amd64' && 'type=gha' || '' }} | |
cache-to: ${{ matrix.platform == 'linux/amd64' && 'type=gha,mode=max' || '' }} | |
- name: Export digest | |
run: | | |
mkdir -p ${{ runner.temp }}/digests | |
digest="${{ steps.build.outputs.digest }}" | |
touch "${{ runner.temp }}/digests/${digest#sha256:}" | |
- name: Upload digest | |
uses: actions/upload-artifact@v4 | |
with: | |
name: digests-${{ env.PLATFORM_PAIR }} | |
path: ${{ runner.temp }}/digests/* | |
if-no-files-found: error | |
retention-days: 1 | |
merge-docker-image: | |
runs-on: ubuntu-latest | |
permissions: | |
packages: write | |
needs: | |
- build-docker-image | |
- check-repository | |
- test-win64-exe | |
- build | |
if: needs.check-repository.outputs.is_main_repo == 'true' | |
steps: | |
- name: Convert to lowercase | |
run: | | |
echo "GHCR_REPO_LOWER=$(echo ${{ env.GHCR_REPO }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV | |
- name: Download digests | |
uses: actions/download-artifact@v4 | |
with: | |
path: ${{ runner.temp }}/digests | |
pattern: digests-* | |
merge-multiple: true | |
- name: Login to Docker.io | |
uses: docker/login-action@v3 | |
with: | |
registry: docker.io | |
username: ${{ secrets.DOCKER_USERNAME }} | |
password: ${{ secrets.DOCKER_PASSWORD }} | |
- name: Login to GHCR | |
uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.repository_owner }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Docker meta | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: | | |
${{ env.DOCKERHUB_REPO }} | |
${{ env.GHCR_REPO_LOWER }} | |
tags: | | |
type=raw,value=dev | |
type=raw,value=${{ needs.build.outputs.version }},enable=${{ needs.build.outputs.is_release != '' && 'true' || 'false' }} | |
type=raw,value=latest,enable=${{ needs.build.outputs.is_release != '' && 'true' || 'false' }} | |
- name: Create manifest list and push | |
working-directory: ${{ runner.temp }}/digests | |
run: | | |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
$(printf '${{ env.DOCKERHUB_REPO }}@sha256:%s ' *) | |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
$(printf '${{ env.GHCR_REPO_LOWER }}@sha256:%s ' *) | |
- name: Inspect image | |
run: | | |
docker buildx imagetools inspect ${{ env.DOCKERHUB_REPO }}:${{ steps.meta.outputs.version }} | |
docker buildx imagetools inspect ${{ env.GHCR_REPO_LOWER }}:${{ steps.meta.outputs.version }} | |
build-win64-exe: | |
runs-on: windows-latest | |
needs: | |
- check-repository | |
if: needs.check-repository.outputs.is_main_repo == 'true' | |
steps: | |
- name: 检出代码 | |
uses: actions/checkout@v4 | |
- name: Setup uv with Python ${{ env.WIN_EXE_PYTHON_VERSION }} | |
uses: astral-sh/setup-uv@1edb52594c857e2b5b13128931090f0640537287 # v5.3.0 | |
with: | |
python-version: ${{ env.WIN_EXE_PYTHON_VERSION }} | |
enable-cache: true | |
cache-dependency-glob: "pyproject.toml" | |
- name: 执行所有任务(创建目录、下载、解压、复制文件、安装依赖) | |
shell: pwsh | |
run: | | |
Write-Host "==== 创建必要的目录 ====" | |
New-Item -Path "./build" -ItemType Directory -Force | |
New-Item -Path "./build/runtime" -ItemType Directory -Force | |
New-Item -Path "./dep_build" -ItemType Directory -Force | |
Write-Host "==== 复制代码到 dep_build ====" | |
Get-ChildItem -Path "./" -Exclude "dep_build", "build" | Copy-Item -Destination "./dep_build" -Recurse -Force | |
Write-Host "==== 下载并解压 Python ${{ env.WIN_EXE_PYTHON_VERSION }} ====" | |
Write-Host "pythonUrl: https://www.python.org/ftp/python/${{ env.WIN_EXE_PYTHON_VERSION }}/python-${{ env.WIN_EXE_PYTHON_VERSION }}-embed-amd64.zip" | |
$pythonUrl = "https://www.python.org/ftp/python/${{ env.WIN_EXE_PYTHON_VERSION }}/python-${{ env.WIN_EXE_PYTHON_VERSION }}-embed-amd64.zip" | |
$pythonZip = "./dep_build/python.zip" | |
Invoke-WebRequest -Uri $pythonUrl -OutFile $pythonZip | |
Expand-Archive -Path $pythonZip -DestinationPath "./build/runtime" -Force | |
Write-Host "==== 下载并解压 PyStand ====" | |
$pystandUrl = "https://github.com/skywind3000/PyStand/releases/download/1.1.4/PyStand-v1.1.4-exe.zip" | |
$pystandZip = "./dep_build/PyStand.zip" | |
Invoke-WebRequest -Uri $pystandUrl -OutFile $pystandZip | |
Expand-Archive -Path $pystandZip -DestinationPath "./dep_build/PyStand" -Force | |
Write-Host "==== 复制 PyStand.exe 到 build 并重命名 ====" | |
$pystandExe = "./dep_build/PyStand/PyStand-x64-CLI/PyStand.exe" | |
$destExe = "./build/pdf2zh.exe" | |
if (Test-Path $pystandExe) { | |
Copy-Item -Path $pystandExe -Destination $destExe -Force | |
} else { | |
Write-Host "错误: PyStand.exe 未找到!" | |
exit 1 | |
} | |
Write-Host "==== 创建 Python venv 在 dep_build ====" | |
uv venv ./dep_build/venv | |
./dep_build/venv/Scripts/activate | |
Write-Host "==== 在 venv 环境中安装项目依赖 ====" | |
uv pip install . | |
Write-Host "==== 复制 venv/Lib/site-packages 到 build/ ====" | |
Copy-Item -Path "./dep_build/venv/Lib/site-packages" -Destination "./build/site-packages" -Recurse -Force | |
Write-Host "==== 复制 script/_pystand_static.int 到 build/ ====" | |
$staticFile = "./script/_pystand_static.int" | |
$destStatic = "./build/_pystand_static.int" | |
if (Test-Path $staticFile) { | |
Copy-Item -Path $staticFile -Destination $destStatic -Force | |
} else { | |
Write-Host "错误: script/_pystand_static.int 未找到!" | |
exit 1 | |
} | |
- name: Upload build artifact | |
uses: actions/upload-artifact@v4 | |
with: | |
name: win64-exe | |
path: ./build | |
if-no-files-found: error | |
compression-level: 1 | |
include-hidden-files: true | |
test-win64-exe: | |
needs: | |
- build-win64-exe | |
- check-repository | |
if: needs.check-repository.outputs.is_main_repo == 'true' | |
runs-on: windows-latest | |
steps: | |
- name: 检出代码 | |
uses: actions/checkout@v4 | |
- name: Download build artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: win64-exe | |
path: ./build | |
- name: Test show version | |
run: | | |
./build/pdf2zh.exe --version | |
- name: Test - Translate a PDF file with plain text only | |
run: | | |
./build/pdf2zh.exe ./test/file/translate.cli.plain.text.pdf -o ./test/file | |
- name: Test - Translate a PDF file figure | |
run: | | |
./build/pdf2zh.exe ./test/file/translate.cli.text.with.figure.pdf -o ./test/file | |
- name: Upload test results | |
uses: actions/upload-artifact@v4 | |
with: | |
name: test-results | |
path: ./test/file/ | |
release-draft: | |
name: Release Draft Tasks | |
needs: | |
- check-repository | |
- build | |
- publish-to-pypi | |
- publish-to-testpypi | |
- merge-docker-image | |
- test-win64-exe | |
if: | | |
always() && needs.check-repository.outputs.is_main_repo == 'true' && | |
(needs.publish-to-pypi.result == 'success' || needs.publish-to-testpypi.result == 'success') && | |
needs.merge-docker-image.result == 'success' && | |
needs.test-win64-exe.result == 'success' | |
runs-on: ubuntu-latest | |
permissions: | |
contents: write | |
pull-requests: write | |
outputs: | |
tag_name: ${{ steps.release-drafter.outputs.tag_name }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
persist-credentials: true | |
fetch-depth: 2 | |
token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Publish the release notes | |
id: release-drafter | |
uses: release-drafter/release-drafter@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v6.1.0 | |
with: | |
publish: ${{ needs.build.outputs.is_release != '' }} | |
tag: ${{ needs.build.outputs.is_release }} | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
upload-release: | |
needs: [release-draft, check-repository] | |
runs-on: ubuntu-latest | |
if: always() && needs.check-repository.outputs.is_main_repo == 'true' && | |
needs.release-draft.result == 'success' | |
steps: | |
- name: 检出代码 | |
uses: actions/checkout@v4 | |
- name: Download build artifact | |
uses: actions/download-artifact@v4 | |
with: | |
name: win64-exe | |
path: ./build | |
- name: Create release zip | |
run: | | |
zip -9qr "pdf2zh-${{ needs.release-draft.outputs.tag_name }}-win64.zip" ./build/* | |
- name: Upload to latest release | |
env: | |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: | | |
# Get the latest release (including drafts and pre-releases) | |
LATEST_RELEASE=${{ needs.release-draft.outputs.tag_name }} | |
echo "Latest release tag: $LATEST_RELEASE" | |
# Upload the zip file to the release | |
gh release upload "$LATEST_RELEASE" "pdf2zh-${{ needs.release-draft.outputs.tag_name }}-win64.zip" --clobber |