From 1ebd0e6738927b44569147e1a560a54f72dd71bf Mon Sep 17 00:00:00 2001 From: Saagar Date: Mon, 18 May 2026 01:37:56 -0700 Subject: [PATCH] docs: prepare public distribution path - document GitHub Releases as the supported public channel - make PyPI publishing explicitly opt-in - add package metadata and distribution policy checks Tests: ruff check src/ tests/; python3 -m pytest -q -p no:cacheprovider; bash scripts/release.sh; make release; ./dist/audit.pyz --help --- .github/ISSUE_TEMPLATE/bug_report.md | 3 +- CHANGELOG.md | 4 +++ Makefile | 12 ++++--- README.md | 3 +- docs/distribution.md | 48 +++++++++++++++++++++++++ docs/release-gates.md | 9 +++-- pyproject.toml | 20 +++++++++++ scripts/release.sh | 52 ++++++++++++++++++---------- tests/test_distribution_policy.py | 40 +++++++++++++++++++++ 9 files changed, 164 insertions(+), 27 deletions(-) create mode 100644 docs/distribution.md mode change 100755 => 100644 scripts/release.sh create mode 100644 tests/test_distribution_policy.py diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index e1be907..3eb9d1a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -23,4 +23,5 @@ What actually happened. Include the full traceback if applicable. ## Environment - OS: [e.g. macOS 15, Ubuntu 24.04] - Python version: [e.g. 3.11.8] -- Commit: [run edb00ee chore: add Makefile, pyproject.toml, CONTRIBUTING, CHANGELOG, docs] +- Install method: [audit.pyz, uv tool, pipx, local clone] +- Version or commit: [run `audit --version` if available, or `git rev-parse --short HEAD` from a clone] diff --git a/CHANGELOG.md b/CHANGELOG.md index 400c9be..5f79479 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## [Unreleased] +### Changed +- Made PyPI publishing explicitly opt-in while keeping GitHub Releases as the supported public distribution path. +- Added PyPI-ready package metadata and public distribution status documentation. + ## [0.19.0] - 2026-05-11 ### Added - `audit serve` local web UI (FastAPI + HTMX): portfolio dashboard, per-repo drill-down, run history, approval queue, and SSE-streamed `audit run` trigger. Requires `pip install -e '.[serve]'` (Arc F S4.1). diff --git a/Makefile b/Makefile index 326cb6a..9061523 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: install install-dev doctor audit control-center demo benchmark workbook-gate workbook-signoff test lint format type-check run clean release-gate build shiv dist-check release +.PHONY: install install-dev doctor audit control-center demo benchmark workbook-gate workbook-signoff test lint format type-check run clean release-gate build shiv dist-check release publish-pypi PYTHON := python3 USERNAME ?= saagpatel @@ -89,6 +89,10 @@ shiv: shiv -c audit -o dist/audit.pyz . --python "/usr/bin/env python3" @echo "=== dist/audit.pyz ready. Test: ./dist/audit.pyz --help ===" -release: build dist-check - @echo "=== Uploading to PyPI via scripts/release.sh ===" - bash scripts/release.sh +release: build dist-check shiv + @echo "=== Release artifacts are ready in dist/ ===" + @echo "Tag a v* release to publish GitHub Release assets. Use make publish-pypi only after PyPI trusted publishing or credentials are configured." + +publish-pypi: + @echo "=== Publishing wheel + sdist to PyPI via scripts/release.sh ===" + bash scripts/release.sh --publish-pypi diff --git a/README.md b/README.md index f991efc..35f0a2e 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,7 @@ Treat campaign/writeback, GitHub Projects, Notion sync, catalog overrides, score - Workbook tour: [docs/workbook-tour.md](docs/workbook-tour.md) - Extending analyzers: [docs/extending-analyzers.md](docs/extending-analyzers.md) - Release gates: [docs/release-gates.md](docs/release-gates.md) +- Distribution status: [docs/distribution.md](docs/distribution.md) - Project history: [docs/project-history.md](docs/project-history.md) ## Features @@ -137,7 +138,7 @@ Treat campaign/writeback, GitHub Projects, Notion sync, catalog overrides, score ### Installation -The package is published as GitHub release artifacts today. PyPI/package-index publishing is not active yet, so registry commands like `pip install github-repo-auditor` are not the recommended public path. +The package is published as GitHub release artifacts today. PyPI/package-index publishing is not active yet, so registry commands like `pip install github-repo-auditor` are not the recommended public path. See [docs/distribution.md](docs/distribution.md) for the current distribution policy. Fastest no-clone path: diff --git a/docs/distribution.md b/docs/distribution.md new file mode 100644 index 0000000..cce45d7 --- /dev/null +++ b/docs/distribution.md @@ -0,0 +1,48 @@ +# Distribution + +GitHub Repo Auditor is public and currently distributed through GitHub Releases. + +## Current Public Path + +Use the latest release binary when you want the fastest no-clone install: + +```bash +curl -LO https://github.com/saagpatel/GithubRepoAuditor/releases/latest/download/audit.pyz +chmod +x audit.pyz +./audit.pyz --help +``` + +Use the public GitHub source when you want an isolated tool install: + +```bash +uv tool install 'git+https://github.com/saagpatel/GithubRepoAuditor.git' +pipx install 'git+https://github.com/saagpatel/GithubRepoAuditor.git' +``` + +## PyPI Status + +PyPI publishing is not active yet. The package name `github-repo-auditor` was +available when checked during the public-readiness pass on 2026-05-18, but that +can change and should be rechecked immediately before first publication. + +The repository is prepared for a future PyPI release: + +- package metadata lives in `pyproject.toml` +- `make build` creates the wheel and source distribution +- `make dist-check` runs `twine check` +- `scripts/release.sh` builds and checks artifacts by default +- `scripts/release.sh --publish-pypi` is the only script path that uploads to PyPI + +## Activation Checklist + +Before the first PyPI release: + +1. Recheck that the `github-repo-auditor` PyPI name is still available. +2. Create the PyPI project through a first upload or configure Trusted Publishing. +3. Prefer PyPI Trusted Publishing from GitHub Actions over long-lived API tokens. +4. Run the standard and distribution gates from [release-gates.md](release-gates.md). +5. Publish the same version that is tagged on GitHub. +6. Smoke-test `pipx install github-repo-auditor` or `uv tool install github-repo-auditor`. + +Until that checklist is complete, GitHub Releases remain the supported public +distribution channel. diff --git a/docs/release-gates.md b/docs/release-gates.md index 6574554..44c0689 100644 --- a/docs/release-gates.md +++ b/docs/release-gates.md @@ -153,12 +153,17 @@ All three must pass before tagging: and non-PEP 440 tag suffixes can break the release build. - Public hardening releases should use patch versions (`v0.1.x`). Feature releases should move the minor version (`v0.2.0`, `v0.3.0`, and so on). -- TWINE upload to PyPI is manual-only and not part of the current public install - story; CI only checks and uploads to GitHub Releases. +- PyPI upload is explicit opt-in and not part of the current public install story. + `scripts/release.sh` builds and checks artifacts by default; it uploads only when + run as `scripts/release.sh --publish-pypi` with valid credentials. CI only checks + and uploads to GitHub Releases. - The `[serve]` extra is not bundled in the shiv binary by default. Users who need the web UI should install from the GitHub source with the `[serve]` extra or use a local editable clone. +See [distribution.md](distribution.md) for the public distribution policy and the +remaining PyPI activation checklist. + ## Web UI Gate (scope: audit serve) Run when any change touches `src/serve/` or `tests/test_serve.py`. diff --git a/pyproject.toml b/pyproject.toml index d846bf5..910a343 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,24 @@ description = "Automated GitHub portfolio auditor with 12 analysis dimensions" readme = "README.md" requires-python = ">=3.11" license = "MIT" +authors = [{ name = "Saag Patel" }] +keywords = [ + "github", + "portfolio", + "audit", + "repository-analysis", + "developer-tools", +] +classifiers = [ + "Development Status :: 3 - Alpha", + "Environment :: Console", + "Intended Audience :: Developers", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Software Development :: Quality Assurance", + "Topic :: Utilities", +] dependencies = [ "requests>=2.31.0", "python-dateutil>=2.8.0", @@ -51,6 +69,8 @@ build = [ Homepage = "https://github.com/saagpatel/GithubRepoAuditor" Repository = "https://github.com/saagpatel/GithubRepoAuditor" "Bug Tracker" = "https://github.com/saagpatel/GithubRepoAuditor/issues" +Changelog = "https://github.com/saagpatel/GithubRepoAuditor/blob/main/CHANGELOG.md" +Documentation = "https://github.com/saagpatel/GithubRepoAuditor#readme" [project.scripts] audit = "src.cli:main" diff --git a/scripts/release.sh b/scripts/release.sh old mode 100755 new mode 100644 index 72ef855..27a2d1d --- a/scripts/release.sh +++ b/scripts/release.sh @@ -1,23 +1,32 @@ #!/usr/bin/env bash -# scripts/release.sh — PyPI publish workflow for github-repo-auditor +# scripts/release.sh — distribution artifact workflow for github-repo-auditor # # Prerequisites: # pip install build twine shiv (or: pip install ".[build]") # -# Required env vars (one of): +# Required env vars for --publish-pypi (one of): # TWINE_API_TOKEN — PyPI API token (preferred) # TWINE_USERNAME + TWINE_PASSWORD — legacy username/password # # Usage: -# bash scripts/release.sh # build + check + upload to PyPI -# bash scripts/release.sh --dry-run # build + check only, skip upload +# bash scripts/release.sh # build + check only +# bash scripts/release.sh --publish-pypi # build + check + upload to PyPI +# bash scripts/release.sh --dry-run # compatibility alias for build + check only # set -euo pipefail -DRY_RUN=false +PUBLISH_PYPI=false +SKIP_CLEAN=false for arg in "$@"; do case "$arg" in - --dry-run) DRY_RUN=true ;; + --publish-pypi) PUBLISH_PYPI=true ;; + --dry-run) PUBLISH_PYPI=false ;; + --skip-clean) SKIP_CLEAN=true ;; + *) + echo "Unknown argument: $arg" + echo "Usage: bash scripts/release.sh [--publish-pypi] [--dry-run] [--skip-clean]" + exit 2 + ;; esac done @@ -30,9 +39,20 @@ echo "Project root: $PROJECT_ROOT" echo "" # 1. Clean previous artifacts -echo "[1/4] Cleaning dist/" -rm -rf dist/ build/ src/*.egg-info -echo " Done." +echo "[1/4] Cleaning build artifacts..." +if [ "$SKIP_CLEAN" = "true" ]; then + echo " Skipped." +else + python3 - <<'PY' +from pathlib import Path +import shutil + +for path in [Path("dist"), Path("build"), *Path("src").glob("*.egg-info")]: + if path.exists(): + shutil.rmtree(path) +PY + echo " Done." +fi # 2. Build wheel + sdist echo "[2/4] Building wheel + sdist..." @@ -45,11 +65,11 @@ echo "[3/4] Running twine check..." python3 -m twine check dist/* echo " All checks passed." -# 4. Upload (unless --dry-run) -if [ "$DRY_RUN" = "true" ]; then - echo "[4/4] --dry-run set — skipping upload." +# 4. Upload only when explicitly requested. +if [ "$PUBLISH_PYPI" != "true" ]; then + echo "[4/4] PyPI publish not requested — skipping upload." echo "" - echo "=== Dry run complete. Artifacts in dist/ ===" + echo "=== Distribution check complete. Artifacts in dist/ ===" exit 0 fi @@ -70,9 +90,3 @@ fi echo "" echo "=== Upload complete! ===" -echo "" -echo "Next steps:" -echo " 1. Tag this release: git tag v$(python3 -c "import importlib.metadata; print(importlib.metadata.version('github-repo-auditor'))" 2>/dev/null || grep '^version' pyproject.toml | head -1 | cut -d'"' -f2)" -echo " 2. Push the tag: git push origin --tags" -echo " 3. Create GitHub Release and attach dist/audit.pyz (if built)" -echo "" diff --git a/tests/test_distribution_policy.py b/tests/test_distribution_policy.py new file mode 100644 index 0000000..5f5c342 --- /dev/null +++ b/tests/test_distribution_policy.py @@ -0,0 +1,40 @@ +"""Distribution policy checks for the public package surface.""" + +from __future__ import annotations + +import tomllib +from pathlib import Path + +ROOT = Path(__file__).parent.parent + + +def test_pyproject_has_public_package_metadata() -> None: + with open(ROOT / "pyproject.toml", "rb") as fh: + project = tomllib.load(fh)["project"] + + assert project["name"] == "github-repo-auditor" + assert project.get("authors"), "PyPI metadata should include an author entry." + assert project.get("classifiers"), "PyPI metadata should include classifiers." + assert project.get("keywords"), "PyPI metadata should include package keywords." + assert "Documentation" in project.get("urls", {}) + assert "Changelog" in project.get("urls", {}) + + +def test_release_script_requires_explicit_pypi_publish_flag() -> None: + release_script = (ROOT / "scripts" / "release.sh").read_text() + + assert "PUBLISH_PYPI=false" in release_script + assert "--publish-pypi" in release_script + assert 'if [ "$PUBLISH_PYPI" != "true" ]' in release_script + assert "PyPI publish not requested" in release_script + + +def test_distribution_docs_name_supported_public_channel() -> None: + distribution_doc = (ROOT / "docs" / "distribution.md").read_text() + readme = (ROOT / "README.md").read_text() + release_gates = (ROOT / "docs" / "release-gates.md").read_text() + + assert "GitHub Releases remain the supported public" in distribution_doc + assert "PyPI publishing is not active yet" in distribution_doc + assert "docs/distribution.md" in readme + assert "scripts/release.sh --publish-pypi" in release_gates