Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
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
153 changes: 153 additions & 0 deletions .github/workflows/pr-validation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# Format, lint, backend stub, tests. Comments the PR with a status table.
# Also callable from python-publish.yml so a release cannot skip the same gates.

name: Validate

on:
pull_request:
branches: [dev, master]
push:
branches: [dev, master]
workflow_call:

concurrency:
group: pr-validation-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

permissions:
contents: read
pull-requests: write

env:
LANG: C.UTF-8
LC_ALL: C.UTF-8
LANGUAGE: C
ORCSOME3_BUILD_JOBS: "2"

jobs:
validate:
name: Validate
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
with:
persist-credentials: false

- name: Setup Python
uses: actions/setup-python@v7
with:
python-version: "3.12"
cache: pip
cache-dependency-path: pyproject.toml

- name: Install Python dependencies
run: |
python -m pip install -U pip
python -m pip install dbus-next typing_extensions "Cython>=3.0" mypy basedpyright ruff setuptools types-setuptools

- name: Check code formatting
id: formatting
run: make format-check

- name: Lint
id: lint
run: make lint

- name: Install native build dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
git cmake autoconf automake libtool pkg-config meson ninja-build \
libx11-dev libxss-dev libxext-dev libxtst-dev curl xvfb
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"

- name: Cache native libraries
uses: actions/cache@v6
with:
path: |
~/.cache/orcsome3/libs
orcsome3_built_libraries
key: native-${{ runner.os }}-${{ hashFiles('orcsome3/libs/build/**', 'orcsome3/common.py') }}
restore-keys: |
native-${{ runner.os }}-

- name: Build native backend
run: |
if [ -d orcsome3_built_libraries ]; then
make native-fast
else
make native
fi

- name: Validate backend stub
id: stubs
run: make stubs-check

- name: Run tests
id: tests
run: make test

- name: Comment PR status
if: always() && github.event_name == 'pull_request'
uses: actions/github-script@v8
with:
script: |
const checks = {
formatting: '${{ steps.formatting.outcome }}' === 'success',
lint: '${{ steps.lint.outcome }}' === 'success',
stubs: '${{ steps.stubs.outcome }}' === 'success',
tests: '${{ steps.tests.outcome }}' === 'success',
};
const allPassed = Object.values(checks).every(v => v);
const status = allPassed ? 'βœ… All checks passed!' : '❌ Some checks failed';

let body = `## PR Validation Results\n\n${status}\n\n`;
body += '| Check | Status |\n|-------|--------|\n';
body += `| Code formatting (ruff format) | ${checks.formatting ? 'βœ…' : '❌'} |\n`;
body += `| Lint (ruff, mypy, basedpyright, named-args, explicit-types) | ${checks.lint ? 'βœ…' : '❌'} |\n`;
body += `| Backend stub (\`orcsome3_backend.pyi\`) | ${checks.stubs ? 'βœ…' : '❌'} |\n`;
body += `| Tests (unittest) | ${checks.tests ? 'βœ…' : '❌'} |\n`;

if (!checks.formatting) {
body += '\n\n**The code was not properly formatted.** Run:\n\n';
body += '```bash\nmake format\n```\n\nThen commit the changes.';
}
if (!checks.lint) {
body += '\n\n**Lint failed.** Run:\n\n';
body += '```bash\nmake lint\n```';
}
if (!checks.stubs) {
body += '\n\n**Backend stub is stale.** Run:\n\n';
body += '```bash\nmake stubs\n```\n\nThen commit `orcsome3_backend.pyi`. Needs a built `.so` (`make native` / `make native-fast`).';
}
if (!checks.tests) {
body += '\n\n**Tests failed.** Run:\n\n';
body += '```bash\nmake test\n```\n\nX11 tests skip without a display; CI installs Xvfb.';
}

const marker = '## PR Validation Results';
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const existing = comments.find(
(c) => c.user && c.user.type === 'Bot' && c.body && c.body.includes(marker)
);
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}
144 changes: 107 additions & 37 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
@@ -1,52 +1,122 @@
# This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# sdist + manylinux wheels β†’ PyPI on a GitHub Release or Actions β†’ Run workflow.
# `uses:` cannot take ${{ matrix.* }}; pin each cibuildwheel version on its own job.

name: Upload Python Package

on:
release:
types: [published]
workflow_dispatch:

permissions:
contents: read

env:
CIBW_SKIP: "*-musllinux_* *t-*"
CIBW_BEFORE_BUILD: "pip install 'Cython>=3.0'"
CIBW_ENVIRONMENT: "ORCSOME3_BUILD_JOBS=2"
CIBW_TEST_SKIP: "*"

jobs:
deploy:
validate:
uses: ./.github/workflows/pr-validation.yml
permissions:
contents: read

wheels-cp39-plus:
needs: validate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false

- name: Install build dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
git cmake autoconf automake libtool pkg-config meson ninja-build \
libx11-dev libxss-dev libxext-dev libxtst-dev curl
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"

- uses: pypa/cibuildwheel@v4.2.0
env:
CIBW_BUILD: "cp3[9]* cp31*"

- uses: actions/upload-artifact@v7
with:
name: wheels-v4.2.0
path: wheelhouse/*.whl

wheels-cp38:
needs: validate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: '3.x'
- name: Install dependencies
run: |
sudo apt remove -y imagemagick imagemagick-6-common
wget https://imagemagick.org/archive/ImageMagick.tar.gz
mkdir -p ./ImageMagick7
tar xvzf ImageMagick.tar.gz --directory ./ImageMagick7 --strip-components=1
cd ImageMagick7
./configure
make
sudo make install
sudo ldconfig /usr/local/lib

sudo apt remove -y nginx libgd3
sudo apt install -y libev-dev libx11-dev libxss-dev libxext-dev libgd-dev
python -m pip install --upgrade pip
pip install build
- name: Build package
run: |
python -m build --sdist
- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
- uses: actions/checkout@v7
with:
persist-credentials: false

- name: Install build dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
git cmake autoconf automake libtool pkg-config meson ninja-build \
libx11-dev libxss-dev libxext-dev libxtst-dev curl
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"

- uses: pypa/cibuildwheel@v3.4.1
env:
CIBW_BUILD: "cp38-*"

- uses: actions/upload-artifact@v7
with:
name: wheels-v3.4.1
path: wheelhouse/*.whl

build_sdist:
needs: validate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false

- uses: actions/setup-python@v7
with:
python-version: "3.x"

- name: Install dependencies
run: python -m pip install --upgrade pip build

- name: Build sdist
run: python -m build --sdist

- uses: actions/upload-artifact@v7
with:
name: sdist
path: dist/*.tar.gz

pypi-publish:
needs:
- wheels-cp39-plus
- wheels-cp38
- build_sdist
runs-on: ubuntu-latest
permissions:
id-token: write
environment:
name: pypi
url: https://pypi.org/p/orcsome3
steps:
- uses: actions/download-artifact@v8
with:
path: dist
merge-multiple: true

- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: dist/
password: ${{ secrets.PYPI_API_TOKEN }}
49 changes: 48 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ __pycache__/

# Distribution / packaging
.Python
build/
/build/
develop-eggs/
dist/
downloads/
Expand Down Expand Up @@ -151,6 +151,9 @@ dmypy.json
# pytype static type analyzer
.pytype/

# Ruff
.ruff_cache/

# Cython debug symbols
cython_debug/

Expand All @@ -163,3 +166,47 @@ cython_debug/

.vscode/
typings/

# orcsome3 native backend build artifacts
orcsome3_built_libraries/
orcsome3_backend*.so

orcsome3/libs/cython_libs/*
!orcsome3/libs/cython_libs/__init__.py
!orcsome3/libs/cython_libs/orcsome3_backend.pyx

# cairo
!orcsome3/libs/cython_libs/cairo
orcsome3/libs/cython_libs/cairo/*
!orcsome3/libs/cython_libs/cairo/__init__.pxd
!orcsome3/libs/cython_libs/cairo/cairo.pxd

# imagemagick
!orcsome3/libs/cython_libs/imagemagick
orcsome3/libs/cython_libs/imagemagick/*
!orcsome3/libs/cython_libs/imagemagick/__init__.pxd
!orcsome3/libs/cython_libs/imagemagick/imagemagick.pxd

# libev
!orcsome3/libs/cython_libs/libev
orcsome3/libs/cython_libs/libev/*
!orcsome3/libs/cython_libs/libev/__init__.pxd
!orcsome3/libs/cython_libs/libev/libev.pxd

# libgd
!orcsome3/libs/cython_libs/libgd
orcsome3/libs/cython_libs/libgd/*
!orcsome3/libs/cython_libs/libgd/__init__.pxd
!orcsome3/libs/cython_libs/libgd/libgd.pxd

# resvg
!orcsome3/libs/cython_libs/resvg
orcsome3/libs/cython_libs/resvg/*
!orcsome3/libs/cython_libs/resvg/__init__.pxd
!orcsome3/libs/cython_libs/resvg/resvg.pxd

# xlib
!orcsome3/libs/cython_libs/xlib
orcsome3/libs/cython_libs/xlib/*
!orcsome3/libs/cython_libs/xlib/__init__.pxd
!orcsome3/libs/cython_libs/xlib/xlib.pxd
4 changes: 4 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include orcsome3_backend.pyi
include orcsome3/py.typed
recursive-include orcsome3/icons *
recursive-include orcsome3/libs/cython_libs *.pxd *.pyx
Loading