diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..78572cc --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,78 @@ +name: CI + +# Every push to devel/release (or a manual run from the UI) tests the code and +# publishes it to the Gitea PyPI registry of the repository owner as a +# post-release of the current version. A version tag (v1.18.0) publishes the +# clean version instead. +on: + push: + branches: [devel, release] + tags: ["v*"] + workflow_dispatch: + +jobs: + # Tested natively on both architectures the library runs on. + test: + strategy: + matrix: + arch: [amd64, arm64] + runs-on: ${{ matrix.arch }} + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.14" + + - name: Install Poetry + run: pip install "poetry==2.4.1" + + - name: Install dependencies (incl. dev group) + run: poetry install --no-interaction + + - name: Ruff + run: poetry run ruff check . + + - name: Mypy + run: poetry run mypy src + + - name: Pytest + run: poetry run pytest -q + + # Pure-Python wheel (py3-none-any) — built once, works on every architecture. + publish: + needs: test + runs-on: amd64 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.14" + + - name: Install Poetry + run: pip install "poetry==2.4.1" + + # Tag: publish the pyproject version as-is (and refuse a tag that doesn't match it). + # Branch push: the registry rejects re-uploading a version, so every commit gets a + # unique post-release (1.17.0.post12). Post-releases are not pre-releases, so a plain + # `^1.17` constraint picks them up. + - name: Set package version + run: | + VERSION="$(poetry version --short)" + if [ "${{ github.ref_type }}" = "tag" ]; then + if [ "v$VERSION" != "${{ github.ref_name }}" ]; then + echo "Tag ${{ github.ref_name }} does not match pyproject version $VERSION" >&2 + exit 1 + fi + else + poetry version "$VERSION.post${{ github.run_number }}" + fi + echo "Publishing $(poetry version --short) from ${{ github.sha }}" + + - name: Build and publish to Gitea PyPI registry + env: + POETRY_REPOSITORIES_GITEA_URL: https://gitea.doubynet.eu/api/packages/${{ github.repository_owner }}/pypi + POETRY_HTTP_BASIC_GITEA_USERNAME: ${{ github.repository_owner }} + POETRY_HTTP_BASIC_GITEA_PASSWORD: ${{ secrets.REGISTRY_TOKEN }} + run: poetry publish --build -r gitea --no-interaction diff --git a/AGENTS.md b/AGENTS.md index 933fa33..d7639f6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,24 +1,21 @@ # AI Agents - Project Rules -**Document Version:** v8 (independent, incremented on structural changes) +**Document Version:** v9 (independent, incremented on structural changes) Language-agnostic rules for AI assistants (Claude Code, Cursor, Copilot, etc.). -Everything language-specific — package manager, formatter, linter, test framework, -logging library, line length, project layout — lives in the matching design document: +Everything specific — package manager, formatter, linter, test framework, logging library, +line length, project layout, interface conventions — lives in the design documents. -| Project type | Design document | -|--------------------|------------------------------------| -| Python application | `DESIGN_DOCUMENT_PYTHON.md` | -| Python library | `DESIGN_DOCUMENT_PYTHON_MODULE.md` | -| Rust application | `DESIGN_DOCUMENT_RUST.md` | -| Rust library | `DESIGN_DOCUMENT_RUST_LIB.md` | -| Godot | `DESIGN_DOCUMENT_GODOT.md` | +**Find them, do not look them up in a list:** every file matching `DESIGN_DOCUMENT*.md` in the +project root applies to this project. The suffix says what it covers — the language +(`DESIGN_DOCUMENT_PYTHON.md`), whether it is an application or a library +(`..._PYTHON_MODULE.md`), or a part of the system that has conventions of its own +(`..._WEBAPP.md`). A project carries as many as it needs and nothing collides, so no list here +needs maintaining and none can go stale. -The language is part of the file name, so a project that mixes languages carries one design document -per language and nothing collides. - -Where this file and a design document disagree, **the design document wins**. +Where this file and a design document disagree, **the design document wins**. Where two design +documents disagree, the more specific one wins for what it covers. ## First-time setup diff --git a/CHANGELOG.md b/CHANGELOG.md index 57355a5..7c2225f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,11 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Added +- **Gitea CI and package publishing** — `.gitea/workflows/ci.yml` runs ruff, mypy and pytest natively on amd64 and arm64 on every push to `devel`/`release` and then publishes the package to the Gitea PyPI registry (`https://gitea.doubynet.eu/api/packages/Honza/pypi`). A branch push is published as a unique post-release of the current version (`1.17.0.post`); a `v*` tag publishes the clean version, after checking that the tag matches the `pyproject.toml` version. + ### Changed +- `README.md` — installation now points at the Gitea PyPI registry (Poetry `explicit` source / pip index URL) instead of the public PyPI; added a release procedure. - `.gitignore` — stopped ignoring the shared agent documents (`AGENTS.md`, `CLAUDE.md`, `DESIGN_DOCUMENT_MODULE.md`); the section now covers only the Claude Code working files (`.claude/`, `handover.md`). --- diff --git a/README.md b/README.md index 03e91f0..b4deeba 100644 --- a/README.md +++ b/README.md @@ -68,14 +68,39 @@ Note: query **parameters are applied only to the in-memory query**, never to the ## Installation +The package is published to the Gitea PyPI registry, not to the public PyPI. + +With Poetry: + ```bash -pip install sqlmem -# or with Poetry -poetry add sqlmem +poetry source add --priority=explicit gitea https://gitea.doubynet.eu/api/packages/Honza/pypi/simple +poetry add sqlmem --source gitea +``` + +`explicit` priority means only packages pinned to this source (`sqlmem`) are looked up there; every other dependency still comes from PyPI. If the registry is not public, store a Gitea access token (scope `read:package`) once per machine: + +```bash +poetry config http-basic.gitea +``` + +With pip: + +```bash +pip install --index-url https://gitea.doubynet.eu/api/packages/Honza/pypi/simple \ + --extra-index-url https://pypi.org/simple sqlmem ``` Requires Python 3.14. +### Releasing + +Publishing is done by CI (`.gitea/workflows/ci.yml`) after tests pass on amd64 and arm64: + +- **Every push to `devel`/`release`** publishes the commit as a post-release of the current `pyproject.toml` version — `.post`, e.g. `1.17.0.post12`. The registry does not accept re-uploading an existing version, so each commit needs its own number. Post-releases are not pre-releases, so a plain `^1.17` constraint picks them up. +- **Pushing a version tag** publishes the clean version: update `CHANGELOG.md`, bump `version` (`poetry version `), commit, then `git tag v && git push origin v`. A tag that does not match the `pyproject.toml` version is refused. + +The job authenticates with the `REGISTRY_TOKEN` secret (scope `write:package`). + ## Quick start ```python