Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .github/workflows/docker-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Build Docker Image

on:
push:
branches: [ main, master, develop ]
pull_request:
branches: [ main, master, develop ]
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: recursive

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build Docker image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: false
tags: python-mapnik:latest
cache-from: type=gha,scope=buildkit-python-mapnik
cache-to: type=gha,mode=max,scope=buildkit-python-mapnik
load: true

- name: Cache uv virtual environment (for container tests)
uses: actions/cache@v5
with:
path: .venv
key: venv-docker-${{ runner.os }}-${{ hashFiles('uv.lock', 'pyproject.toml', 'setup.py') }}
restore-keys: |
venv-docker-${{ runner.os }}-

- name: Run tests in Docker container
run: |
docker run --rm \
-v ${{ github.workspace }}:/workspace \
-w /workspace/test/python_tests \
python-mapnik:latest \
sh -c "uv sync --extra test && uv run pytest . -v"
136 changes: 136 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
name: Release

on:
push:
tags:
- 'v*.*.*'
workflow_dispatch:
inputs:
tag:
description: 'Tag to release (e.g., v4.2.0)'
required: true
type: string

jobs:
test:
uses: ./.github/workflows/test.yml

build:
needs: test
runs-on: ubuntu-latest
container:
image: python:3.12-bookworm
env:
UV_LINK_MODE: copy
UV_CACHE_DIR: /github/home/.cache/uv
permissions:
actions: write
contents: write

steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: recursive

- name: Cache uv downloads
uses: actions/cache@v5
with:
path: /github/home/.cache/uv
key: uvcache-${{ runner.os }}-${{ hashFiles('uv.lock', 'pyproject.toml') }}
restore-keys: |
uvcache-${{ runner.os }}-

- name: Extract version from tag
id: version
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
VERSION=${{ inputs.tag }}
else
VERSION=${GITHUB_REF#refs/tags/}
fi
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "version_number=${VERSION#v}" >> $GITHUB_OUTPUT

- name: Add Debian sid repository
run: |
echo "deb http://deb.debian.org/debian sid main" >> /etc/apt/sources.list.d/sid.list
echo 'Package: *\nPin: release a=sid\nPin-Priority: 100' > /etc/apt/preferences.d/sid

- name: Install system dependencies
run: |
apt-get update
# Ensure /etc/os-release exists (required by some actions' OS detection).
apt-get install -y base-files
apt-get install -y build-essential pkg-config libbz2-dev
apt-get install -y -t sid libmapnik-dev

- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: false

- name: Build wheel and sdist
run: |
uv build --wheel --sdist

- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 7

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
if: github.event_name == 'push'
with:
tag_name: ${{ steps.version.outputs.version }}
name: Release ${{ steps.version.outputs.version }}
body: |
## Python Mapnik ${{ steps.version.outputs.version_number }}

### Installation

Download the wheel file below and install:
```bash
pip install mapnik-${{ steps.version.outputs.version_number }}-*.whl
```

Or install directly from GitHub:
```bash
pip install https://github.com/${{ github.repository }}/releases/download/${{ steps.version.outputs.version }}/mapnik-${{ steps.version.outputs.version_number }}-cp312-cp312-linux_x86_64.whl
```

Or install from source:
```bash
pip install git+https://github.com/${{ github.repository }}.git@${{ steps.version.outputs.version }}
```

### Requirements

- Python >= 3.8
- Mapnik >= 4.0.0

### Changes

See [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ steps.version.outputs.version }}/CHANGELOG.md) for details.
files: |
dist/*.whl
dist/*.tar.gz
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Summary
run: |
echo "## Release Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ Released version: **${{ steps.version.outputs.version }}**" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Artifacts Built:" >> $GITHUB_STEP_SUMMARY
ls -lh dist/ >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Distribution:" >> $GITHUB_STEP_SUMMARY
echo "- GitHub Release: ✅" >> $GITHUB_STEP_SUMMARY
111 changes: 111 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
name: Test

on:
push:
branches: [ main, master, develop ]
pull_request:
branches: [ main, master, develop ]
workflow_dispatch:
workflow_call:

jobs:
test:
runs-on: ubuntu-latest
container:
image: python:3.12-bookworm
env:
UV_LINK_MODE: copy
UV_CACHE_DIR: /github/home/.cache/uv
permissions:
actions: write
contents: read
checks: write

steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: recursive

- name: Cache uv downloads
uses: actions/cache@v5
with:
path: /github/home/.cache/uv
key: uvcache-${{ runner.os }}-${{ hashFiles('uv.lock', 'pyproject.toml') }}
restore-keys: |
uvcache-${{ runner.os }}-

- name: Cache uv virtual environment and build artifacts
uses: actions/cache@v5
with:
path: .venv
key: venv-${{ runner.os }}-${{ hashFiles('uv.lock', 'pyproject.toml', 'setup.py') }}-${{ hashFiles('src/**/*.cpp', 'src/**/*.hpp', 'packaging/**/*.py') }}
restore-keys: |
venv-${{ runner.os }}-${{ hashFiles('uv.lock', 'pyproject.toml', 'setup.py') }}-
venv-${{ runner.os }}-

- name: Add Debian sid repository
run: |
echo "deb http://deb.debian.org/debian sid main" >> /etc/apt/sources.list.d/sid.list
echo 'Package: *\nPin: release a=sid\nPin-Priority: 100' > /etc/apt/preferences.d/sid

- name: Install system dependencies
run: |
apt-get update
# Ensure /etc/os-release exists (required by some actions' OS detection).
apt-get install -y base-files
apt-get install -y build-essential pkg-config libbz2-dev
apt-get install -y -t sid libmapnik-dev fonts-noto-cjk

- name: Install uv
uses: astral-sh/setup-uv@v7
with:
# Work around container-job failures determining Linux distribution during
# setup-uv's built-in caching path; we cache UV_CACHE_DIR ourselves above.
enable-cache: false

- name: Install Python dependencies and build package
run: |
# Use lockfile when present; avoid doing two full syncs (which can rebuild twice).
if [ -f uv.lock ]; then
uv sync --extra test --frozen --verbose
else
uv sync --extra test --verbose
fi

- name: Run tests with coverage
run: |
uv run pytest test/python_tests -v \
--cov=mapnik \
--cov-report=term \
--cov-report=xml:coverage.xml \
--cov-report=html:htmlcov \
--junitxml=junit.xml

- name: Upload coverage reports
uses: actions/upload-artifact@v4
if: always()
with:
name: coverage-reports
path: |
coverage.xml
htmlcov/
junit.xml
retention-days: 30

- name: Publish test results
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
with:
files: junit.xml
check_name: Test Results
comment_mode: off

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
if: always()
with:
files: ./coverage.xml
flags: unittests
name: python-mapnik-coverage
fail_ci_if_error: false
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*.dylib
build/
dist/
mapnik/paths.py
packaging/mapnik/paths.py
*.egg-info/
.eggs/
.mason/
Expand Down
49 changes: 49 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
FROM python:3.14-rc-bookworm

# Build-time proxy support (affects apt/uv/etc. during docker build)
ARG http_proxy
ARG https_proxy
ARG no_proxy
ENV http_proxy=${http_proxy} \
https_proxy=${https_proxy} \
no_proxy=${no_proxy} \
HTTP_PROXY=${http_proxy} \
HTTPS_PROXY=${https_proxy} \
NO_PROXY=${no_proxy}

# 添加 Debian sid 仓库以获取 Mapnik 4.2
RUN echo "deb http://deb.debian.org/debian sid main" >> /etc/apt/sources.list.d/sid.list && \
echo 'Package: *\nPin: release a=sid\nPin-Priority: 100' > /etc/apt/preferences.d/sid

# 安装必要的工具
RUN apt-get update && \
apt-get install -y \
build-essential \
pkg-config

# 安装 Mapnik 4.2 和必要的开发工具
RUN apt-get install -y -t sid \
libmapnik-dev \
fonts-noto-cjk

# 需要额外的依赖写在这里,避免缓存失效。上面的依赖安装起来时间很长
RUN apt-get install -y \
libbz2-dev \
&& rm -rf /var/lib/apt/lists/*

# 安装 uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

# 复制依赖文件
COPY pyproject.toml .
COPY uv.lock* ./

# 复制源代码文件(构建本地包所需)
COPY src/ src/
COPY setup.py .
COPY build.py .
COPY packaging/ packaging/

# 安装 Python 依赖(包括构建本地 python-mapnik)
# 使用 --verbose 显示详细的编译日志
RUN uv sync --frozen --no-dev --verbose || uv sync --no-dev --verbose
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ Once you have installed you can test the package by running:
pytest test/python_tests/
```

## UV Sync via Docker



```
docker run --rm -it \
-e http_proxy -e https_proxy -e no_proxy \
-v "$(pwd):/workspace" \
-w /workspace \
python-mapnik:local \
uv sync --verbose
```
Loading