diff --git a/.gitea/workflows/publish-python-package.yml b/.gitea/workflows/publish-python-package.yml new file mode 100644 index 0000000..f0cfbcd --- /dev/null +++ b/.gitea/workflows/publish-python-package.yml @@ -0,0 +1,37 @@ +name: Publish Python package + +on: + push: + tags: + - "v*" + workflow_dispatch: + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - name: Check out source + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install packaging tools + run: python -m pip install --upgrade build twine + + - name: Build distributions + run: python -m build + + - name: Validate distributions + run: python -m twine check dist/* + + - name: Upload to Gitea PyPI + env: + TWINE_USERNAME: ${{ secrets.GITEA_PACKAGE_USER }} + TWINE_PASSWORD: ${{ secrets.GITEA_PACKAGE_TOKEN }} + run: >- + python -m twine upload + --repository-url https://gitea.coulomb.social/api/packages/coulomb/pypi + dist/* diff --git a/Makefile b/Makefile index ab44021..f558e68 100644 --- a/Makefile +++ b/Makefile @@ -37,6 +37,9 @@ help: ## Show issue core capability help @echo " test-integration Run integration tests only" @echo " test-cov Run tests with coverage report" @echo " test-verbose Run tests with verbose output" + @echo " package Build source and wheel distributions" + @echo " package-check Build and validate distributions" + @echo " publish-gitea Publish distributions to Gitea PyPI" @echo "" @echo "Feedback & Continuous Improvement:" @echo " feedback MSG=\"...\" Submit feedback about issue-core" @@ -60,6 +63,10 @@ help: ## Show issue core capability help # Check if issue command is available ISSUE_CLI := $(shell command -v issue 2> /dev/null) +PYTHON ?= python3 +GITEA_PACKAGE_OWNER ?= coulomb +GITEA_PYPI_REPOSITORY_URL ?= https://gitea.coulomb.social/api/packages/$(GITEA_PACKAGE_OWNER)/pypi + # Core Issue Operations .PHONY: issue-list issue-list: ## List all issues from configured backend @@ -209,6 +216,28 @@ test-cov: ## Run tests with coverage report (local development) test-verbose: ## Run tests with verbose output (local development) pytest tests/ -v +.PHONY: clean-dist +clean-dist: ## Remove local Python package build artifacts + rm -rf build/ dist/ *.egg-info/ + +.PHONY: package +package: clean-dist ## Build source and wheel distributions + $(PYTHON) -m build + +.PHONY: package-check +package-check: package ## Build and validate source/wheel distributions + $(PYTHON) -m twine check dist/* + +.PHONY: publish-gitea +publish-gitea: package-check ## Publish distributions to the Coulomb Gitea PyPI registry +ifndef TWINE_USERNAME + $(error TWINE_USERNAME is required) +endif +ifndef TWINE_PASSWORD + $(error TWINE_PASSWORD is required) +endif + $(PYTHON) -m twine upload --repository-url "$(GITEA_PYPI_REPOSITORY_URL)" dist/* + # Feedback and Continuous Improvement .PHONY: feedback feedback: ## Submit feedback (Usage: make feedback MSG="your feedback") @@ -358,4 +387,4 @@ capability-info: ## Show capability information @echo "Supported backends: Local SQLite, GitHub, GitLab, Gitea" @echo "Key features: Repository-aware, offline-capable, unified interface" @echo "Targets:" - @$(MAKE) --no-print-directory help | grep "^ " | sed 's/^ / /' \ No newline at end of file + @$(MAKE) --no-print-directory help | grep "^ " | sed 's/^ / /' diff --git a/docs/package-release.md b/docs/package-release.md new file mode 100644 index 0000000..fd6d3fd --- /dev/null +++ b/docs/package-release.md @@ -0,0 +1,51 @@ +# Python Package Release + +`issue-core` publishes as the `issue-core` Python package. The Railiance +application deployment path expects the `0.2.x` series to be available from the +Coulomb Gitea PyPI registry. + +## Local Release + +Build and validate the release artifacts: + +```bash +make package-check +``` + +Publish to the Coulomb organization registry: + +```bash +TWINE_USERNAME= \ +TWINE_PASSWORD= \ +make publish-gitea +``` + +The package endpoint is: + +```text +https://gitea.coulomb.social/api/packages/coulomb/pypi +``` + +The matching simple index for consumers is: + +```text +https://gitea.coulomb.social/api/packages/coulomb/pypi/simple/ +``` + +Do not commit tokenized package index URLs. CI and local Docker builds should +inject registry credentials through environment variables or BuildKit secrets. + +## Gitea Actions Release + +The `.gitea/workflows/publish-python-package.yml` workflow publishes on tags +matching `v*`. Configure these repository secrets before cutting a release: + +- `GITEA_PACKAGE_USER` +- `GITEA_PACKAGE_TOKEN` + +Release `0.2.0` with: + +```bash +git tag v0.2.0 +git push origin v0.2.0 +``` diff --git a/pyproject.toml b/pyproject.toml index ddaafd0..063c453 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=45", "wheel", "setuptools-scm[toml]>=6.2"] +requires = ["setuptools>=61,<77", "wheel"] build-backend = "setuptools.build_meta" [project] @@ -37,9 +37,11 @@ dynamic = ["version"] [project.optional-dependencies] dev = [ + "build>=1.3", "pytest>=6.0", "pytest-cov>=2.0", "pytest-mock>=3.0", + "twine>=6.0", "black>=22.0", "isort>=5.0", "flake8>=4.0", @@ -48,7 +50,7 @@ dev = [ "httpx>=0.27", "fastapi>=0.110,<1.0", "pydantic>=2.0,<3.0", -] +] docs = [ "sphinx>=4.0", "sphinx-rtd-theme>=1.0", @@ -170,4 +172,4 @@ exclude_lines = [ "if __name__ == .__main__.:", "class .*\\bProtocol\\):", "@(abc\\.)?abstractmethod", -] \ No newline at end of file +] diff --git a/workplans/ISSUE-WP-0002-gitea-pypi-publication.md b/workplans/ISSUE-WP-0002-gitea-pypi-publication.md new file mode 100644 index 0000000..65b522a --- /dev/null +++ b/workplans/ISSUE-WP-0002-gitea-pypi-publication.md @@ -0,0 +1,83 @@ +--- +id: ISSUE-WP-0002 +type: workplan +title: "Publish issue-core to Gitea PyPI" +domain: custodian +repo: issue-core +status: blocked +owner: codex +topic_slug: custodian +created: "2026-05-23" +updated: "2026-05-23" +state_hub_workstream_id: "87a5dcb6-5b2c-4d3f-8d5c-e265889b0fc6" +--- + +# Publish issue-core to Gitea PyPI + +`issue-core` needs a first real Python package release in the Coulomb Gitea +package registry so downstream applications can depend on a versioned package +instead of a sibling checkout path. + +## Publish and verify the Gitea PyPI package + +```task +id: ISSUE-WP-0002-T01 +status: blocked +priority: high +state_hub_task_id: "f0df7dbc-b55d-4835-a528-f44a329efb0e" +``` + +**Problem.** `vergabe-teilnahme` and future Railiance S5 apps need +`issue-core` as a normal package dependency. A local dependency such as +`issue-core @ file:///home/worsch/issue-core` makes Docker builds depend on a +specific operator workstation and forces non-portable BuildKit named contexts. + +**Current state.** The repo has package release plumbing prepared: + +- `make package-check` builds and validates `issue-core==0.2.0`. +- `make publish-gitea` uploads `dist/*` to the Coulomb Gitea PyPI endpoint. +- `.gitea/workflows/publish-python-package.yml` can publish on `v*` tags once + package registry secrets exist. +- `docs/package-release.md` documents local and tag-based publishing. + +**Blocker.** Publishing requires a Gitea package username/token with permission +to upload to: + +```text +https://gitea.coulomb.social/api/packages/coulomb/pypi +``` + +No publish credentials are currently available in the shell or standard package +config files. + +**Implementation steps.** + +1. Configure Gitea repository or organization secrets: + `GITEA_PACKAGE_USER` and `GITEA_PACKAGE_TOKEN`. +2. Publish `issue-core==0.2.0` either by pushing tag `v0.2.0` or by running: + + ```bash + TWINE_USERNAME= \ + TWINE_PASSWORD= \ + make publish-gitea + ``` + +3. Verify the simple index exposes the package: + + ```bash + curl -fsS https://gitea.coulomb.social/api/packages/coulomb/pypi/simple/issue-core/ + ``` + +4. Verify a clean environment can install the package from the Gitea simple + index with credentials injected outside Git. +5. Coordinate with `vergabe-teilnahme` to regenerate its `uv.lock` from the + published package and confirm its Docker build no longer needs the sibling + `issue-core` checkout. + +**Done when.** + +- `issue-core==0.2.0` is visible in the Coulomb Gitea PyPI simple index. +- A clean Python environment can install `issue-core>=0.2,<0.3` from Gitea. +- The publish workflow has the required secrets and a documented release path. +- The Railiance app deployment blocker can be closed without relying on local + path dependencies.