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
157 changes: 157 additions & 0 deletions .github/workflows/publish-micropython-lib.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# Publish pure-Python graphics to micropython-lib, MIP index, and TestPyPI (graphics-py).
# Native graphics-cmod wheels are published by publish-testpypi.yml on the same tag.
#
# Release trigger: push tag vX.Y.Z (see scripts/publish_release_tag.sh).
#
# Secrets:
# MICROPYTHON_LIB_DEPLOY_TOKEN — PAT with contents:write on PyDevices/micropython-lib
# TESTPYPI_API_TOKEN — TestPyPI API token

name: Publish micropython-lib

on:
push:
tags:
- 'v*.*.*'
workflow_dispatch:
inputs:
version:
description: Semver X.Y.Z
type: string
required: false
sync_sources:
description: Sync graphics into micropython-lib
type: boolean
default: true
upload_testpypi:
description: Upload graphics-py wheels to TestPyPI
type: boolean
default: false
publish_mip_index:
description: Rebuild mip/PyDevices and push gh-pages
type: boolean
default: true
commit_message:
description: micropython-lib commit message
type: string
required: false

permissions:
contents: read

# Sibling repos also push to micropython-lib; scripts rebase-retry on conflict.
concurrency:
group: publish-micropython-lib-${{ github.repository }}
cancel-in-progress: false

jobs:
publish:
runs-on: ubuntu-latest
if: github.repository == 'PyDevices/graphics'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Resolve release version
id: version
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
normalize() {
local v="${1#v}"
v="$(echo "$v" | tr -d '[:space:]')"
if [[ ! "$v" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
echo "Invalid semver: $1" >&2
exit 1
fi
echo "$v"
}
if [[ "${{ github.event_name }}" == "push" ]]; then
VERSION="$(normalize "${GITHUB_REF_NAME}")"
elif [[ -n "${INPUT_VERSION:-}" ]]; then
VERSION="$(normalize "$INPUT_VERSION")"
else
TAG="$(git describe --tags --exact-match 2>/dev/null || true)"
if [[ -z "$TAG" ]]; then
echo "Set version input or run from a vX.Y.Z tag." >&2
exit 1
fi
VERSION="$(normalize "$TAG")"
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Publishing graphics-py / MIP release $VERSION"

- name: Verify publish secrets
env:
DEPLOY_TOKEN: ${{ secrets.MICROPYTHON_LIB_DEPLOY_TOKEN }}
TESTPYPI_TOKEN: ${{ secrets.TESTPYPI_API_TOKEN }}
run: |
set -euo pipefail
missing=()
if [[ -z "${DEPLOY_TOKEN}" ]]; then
missing+=("MICROPYTHON_LIB_DEPLOY_TOKEN")
fi
if [[ "${{ github.event_name }}" == "push" || "${{ inputs.upload_testpypi }}" == "true" ]]; then
if [[ -z "${TESTPYPI_TOKEN}" ]]; then
missing+=("TESTPYPI_API_TOKEN")
fi
fi
if [[ ${#missing[@]} -gt 0 ]]; then
echo "::error::GitHub did not supply secrets to PyDevices/graphics: ${missing[*]}"
echo "Org Settings → Secrets → Actions → each secret → Repository access → include graphics."
exit 1
fi

- uses: actions/checkout@v4
with:
repository: PyDevices/micropython-lib
ref: PyDevices
path: micropython-lib
token: ${{ secrets.MICROPYTHON_LIB_DEPLOY_TOKEN }}

- uses: actions/setup-python@v5
with:
python-version: '3.13'

- name: Install publish tools
if: github.event_name == 'push' || inputs.upload_testpypi == true
run: pip install hatch twine

- name: Configure micropython-lib git
run: |
git -C micropython-lib config user.name 'github-actions[bot]'
git -C micropython-lib config user.email 'github-actions[bot]@users.noreply.github.com'
git -C micropython-lib remote set-url origin \
"https://x-access-token:${{ secrets.MICROPYTHON_LIB_DEPLOY_TOKEN }}@github.com/PyDevices/micropython-lib.git"

- name: Sync graphics into micropython-lib
if: github.event_name == 'push' || inputs.sync_sources == true
env:
MICROPYTHON_LIB_DIR: ${{ github.workspace }}/micropython-lib
GRAPHICS_VERSION: ${{ steps.version.outputs.version }}
TESTPYPI_API_TOKEN: ${{ secrets.TESTPYPI_API_TOKEN }}
run: |
VERSION="${{ steps.version.outputs.version }}"
MSG="${{ inputs.commit_message }}"
if [[ -z "$MSG" ]]; then
MSG="graphics: Release v${VERSION} (${GITHUB_SHA::7})."
fi
EXTRA=(--commit-message "$MSG" --push)
if [[ "${{ github.event_name }}" != "push" && "${{ inputs.upload_testpypi }}" != "true" ]]; then
EXTRA=(--skip-pypi --commit-message "$MSG" --push)
fi
chmod +x scripts/publish_micropython_lib.sh
./scripts/publish_micropython_lib.sh "${EXTRA[@]}"

- name: Publish MIP index to gh-pages
if: github.event_name == 'push' || inputs.publish_mip_index == true
env:
MICROPYTHON_LIB_DIR: ${{ github.workspace }}/micropython-lib
GRAPHICS_DIR: ${{ github.workspace }}
MICROPYTHON_DIR: /tmp/micropython
MIP_INDEX_OUTPUT: /tmp/mip-index
run: |
chmod +x scripts/publish_mip_ghpages.sh
./scripts/publish_mip_ghpages.sh
10 changes: 8 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
.venv/
__pycache__/
*.egg-info/
*.py[cod]
*.o
*.a
*.so
*.pyd
*.egg
*.egg-info/
.eggs/
build/
dist/
wheelhouse/
VERSION
graphics_cmod.egg-info/

docs/node_modules/
docs/dist/

# Cursor IDE throwaways (do not ignore the whole .cursor/ tree)
.cursor/debug*
.cursor/plans/
wheels/
47 changes: 47 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# AGENTS.md — graphics

Native and pure-Python **graphics** (`import graphics`) for MicroPython,
CircuitPython, and CPython. Prefer `graphics-cmod` on desktop/Android when
available; otherwise `graphics-py` / MIP `graphics`.

## Layout

- Root: `micropython.mk`, `micropython.cmake`, `circuitpython.mk`, `setup.py`,
patch scripts — build glue stays here for `USER_C_MODULES` discovery
- `src/` — all `.c` sources (shared core + MP/CP bindings + CPython extension)
- `include/` — shared headers (`gfx_*.h`, `font_8x*.h`, `graphics_qstrdefs.h`)
- `lib/graphics/` — pure-Python package (same public API as the cmod)
- `tests/` — native smoke and parity scripts
- No `.c` / `.h` at repo root

## Smoke

```bash
# native
python3 -m venv .venv
echo 0.0.0 > VERSION
.venv/bin/pip install -e .
.venv/bin/python tests/test_area.py
.venv/bin/python tests/test_graphics.py

# pure Python
PYTHONPATH=lib .venv/bin/python -c "import graphics; assert graphics.implementation() == 'graphics_python'"
```

## Publishing

One tag `vX.Y.Z` publishes:

1. **graphics-cmod** — `publish-testpypi.yml` (cibuildwheel)
2. **graphics-py** + MIP — `publish-micropython-lib.yml` (micropython-lib + TestPyPI + gh-pages)

See `PUBLISHING.md`. Next shared version continues the `graphics-cmod` line
(`v0.0.9` → `v0.0.10`).

## After C changes

Refresh pydisplay’s committed runtimes with `../build_pydisplay_runtimes.sh`
from the cmods workspace root when the usermod is linked into those interpreters.

Font C headers: `python3 scripts/sync_fonts.py` (source of truth is
`lib/graphics/_font_8x*.py`).
Loading
Loading