# SPDX-FileCopyrightText: 2022 James R. Barlow # SPDX-License-Identifier: MPL-2.0 name: Test and deploy on: push: branches: - main - ci - release/* - feature/* paths-ignore: - README* pull_request: jobs: test_linux: name: Test ${{ matrix.os }} with Python ${{ matrix.python }} runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-22.04, ubuntu-24.04] python: ["3.11", "3.12", "3.13", "3.14"] include: - os: ubuntu-22.04 tesseract_ppa: "ppa" python: "3.11" env: OS: ${{ matrix.os }} PYTHON: ${{ matrix.python }} steps: - uses: actions/checkout@v6 - name: Install uv uses: astral-sh/setup-uv@v7 with: version: "0.9.x" - name: "Set up Python" uses: actions/setup-python@v6 with: python-version: ${{ matrix.python }} - name: Install Tesseract from PPA if: matrix.tesseract_ppa == 'ppa' run: | sudo add-apt-repository -y ppa:alex-p/tesseract-ocr5 - name: Install common packages run: | sudo apt-get update sudo apt-get install -y --no-install-recommends \ curl \ fonts-noto-core \ fonts-noto-cjk \ ghostscript \ jbig2dec \ img2pdf \ libexempi8 \ libffi-dev \ libsm6 libxext6 libxrender-dev \ pngquant \ poppler-utils \ tesseract-ocr \ tesseract-ocr-deu \ tesseract-ocr-eng \ tesseract-ocr-osd \ unpaper \ zlib1g - name: Install Python packages run: | uv sync --group test - name: Report versions run: | tesseract --version gs --version pngquant --version unpaper --version uv run --no-dev img2pdf --version - name: Test run: | uv run --no-dev pytest --cov-report xml --cov=ocrmypdf --cov=tests/ -n0 tests/ - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: files: ./coverage.xml env_vars: OS,PYTHON test_macos: name: Test macOS runs-on: ${{ matrix.os }} strategy: matrix: os: [macos-latest] python: ["3.11", "3.12", "3.13", "3.14"] env: OS: ${{ matrix.os }} PYTHON: ${{ matrix.python }} steps: - uses: actions/checkout@v6 - name: Install Homebrew deps continue-on-error: true run: | brew update brew install \ exempi \ ghostscript \ jbig2enc \ openjpeg \ pngquant \ poppler \ tesseract \ verapdf - name: Install uv uses: astral-sh/setup-uv@v7 with: version: "0.9.x" - name: "Set up Python" uses: actions/setup-python@v6 with: python-version: ${{ matrix.python }} - name: Install Python packages run: | uv sync --group test - name: Report versions run: | tesseract --version gs --version pngquant --version uv run --no-dev img2pdf --version - name: Test run: | uv run --no-dev pytest --cov-report xml --cov=ocrmypdf --cov=tests/ -n0 tests/ - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: files: ./coverage.xml env_vars: OS,PYTHON test_windows: name: Test Windows runs-on: ${{ matrix.os }} strategy: matrix: os: [windows-latest] python: ["3.11", "3.12", "3.13", "3.14"] env: OS: ${{ matrix.os }} PYTHON: ${{ matrix.python }} steps: - uses: actions/checkout@v6 - name: Install uv uses: astral-sh/setup-uv@v7 with: version: "0.9.x" - name: "Set up Python" uses: actions/setup-python@v6 with: python-version: ${{ matrix.python }} - name: Install system packages run: | choco install --yes --no-progress tesseract choco install --yes --no-progress --ignore-checksums ghostscript --version 9.56.1 choco install --yes --no-progress poppler --version=25.11.0 - name: Install Python packages run: | uv sync --group test - name: Test run: | uv run --no-dev pytest --cov-report xml --cov=ocrmypdf --cov=tests/ -n0 tests/ - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: files: ./coverage.xml env_vars: OS,PYTHON wheel_sdist_linux: name: Build sdist and wheels runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Install uv uses: astral-sh/setup-uv@v7 with: version: "0.9.x" - name: Make wheels and sdist run: | uv build --sdist --wheel - uses: actions/upload-artifact@v6 with: name: artifact path: | ./dist/*.whl ./dist/*.tar.gz stage_release: name: Stage release artifacts needs: [wheel_sdist_linux, test_linux, test_macos, test_windows] runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' permissions: contents: write steps: - uses: actions/checkout@v6 - uses: actions/download-artifact@v7 with: name: artifact path: dist - name: Read version from source id: version run: | VERSION=$(python3 -c "exec(open('src/ocrmypdf/_version.py').read()); print(__version__)") echo "version=$VERSION" >> $GITHUB_OUTPUT - name: Create or update draft release env: GITHUB_TOKEN: ${{ github.token }} run: | TAG="v${{ steps.version.outputs.version }}" # Delete existing draft release if it exists (ignore errors) gh release delete "$TAG" --yes 2>/dev/null || true # Create new draft release with all artifacts gh release create "$TAG" \ --draft \ --title "$TAG" \ --notes "Draft release - will be updated when tag is pushed" \ dist/* docker_ubuntu: name: Build Ubuntu-based Docker image needs: [wheel_sdist_linux, test_linux, test_macos, test_windows] runs-on: ubuntu-latest if: github.event_name != 'pull_request' steps: - name: Set image tag to release or branch run: echo "DOCKER_IMAGE_TAG=${GITHUB_REF##*/}" >> $GITHUB_ENV - name: If main, set to latest run: echo 'DOCKER_IMAGE_TAG=latest' >> $GITHUB_ENV if: env.DOCKER_IMAGE_TAG == 'main' - name: Set Docker Hub repository to username run: echo "DOCKER_REPOSITORY=jbarlow83" >> $GITHUB_ENV - name: Set image name run: echo "DOCKER_IMAGE_NAME=ocrmypdf" >> $GITHUB_ENV - uses: actions/checkout@v6 - name: Login to Docker Hub uses: docker/login-action@v3 with: username: jbarlow83 password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx id: buildx uses: docker/setup-buildx-action@v3 - name: Print image tag run: echo "Building image ${DOCKER_REPOSITORY}/${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG}" - name: Build run: | docker buildx build \ --push \ --platform linux/arm64/v8,linux/amd64 \ --tag "${DOCKER_REPOSITORY}/${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG}" \ --tag "${DOCKER_REPOSITORY}/${DOCKER_IMAGE_NAME}-ubuntu:${DOCKER_IMAGE_TAG}" \ --file .docker/Dockerfile . docker_alpine: name: Build Alpine-based Docker images needs: [wheel_sdist_linux, test_linux, test_macos, test_windows] runs-on: ubuntu-latest if: github.event_name != 'pull_request' steps: - name: Set image tag to release or branch run: echo "DOCKER_IMAGE_TAG=${GITHUB_REF##*/}" >> $GITHUB_ENV - name: If main, set to latest run: echo 'DOCKER_IMAGE_TAG=latest' >> $GITHUB_ENV if: env.DOCKER_IMAGE_TAG == 'main' - name: Set Docker Hub repository to username run: echo "DOCKER_REPOSITORY=jbarlow83" >> $GITHUB_ENV - name: Set image name run: echo "DOCKER_IMAGE_NAME=ocrmypdf-alpine" >> $GITHUB_ENV - uses: actions/checkout@v6 - name: Login to Docker Hub uses: docker/login-action@v3 with: username: jbarlow83 password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx id: buildx uses: docker/setup-buildx-action@v3 - name: Print image tag run: echo "Building image ${DOCKER_REPOSITORY}/${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG}" - name: Build run: | docker buildx build \ --push \ --platform linux/amd64,linux/arm64 \ --tag "${DOCKER_REPOSITORY}/${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG}" \ --file .docker/Dockerfile.alpine .