diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..ae90005 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,54 @@ +name: Release + +# Publishes to PyPI when a version tag is pushed (for example `v0.3.0`). +# Uses PyPI Trusted Publishing (OIDC), so no API token is stored in the repo. +# One-time setup: add a trusted publisher on https://pypi.org/manage/account/publishing/ +# owner: Shellghostt, repository: WebVac, workflow: release.yml +# The tag must match `webvac.__version__` in `webvac/__init__.py`. + +on: + push: + tags: + - "v*" + +permissions: + contents: read + id-token: write + +jobs: + publish: + name: Build and publish to PyPI + runs-on: ubuntu-latest + + steps: + - name: Check out the repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Check tag matches package version + run: | + python - <<'PY' + import os + import pathlib + import re + + source = pathlib.Path("webvac/__init__.py").read_text(encoding="utf-8") + version = re.search(r'__version__\s*=\s*"([^"]+)"', source).group(1) + tag = os.environ["GITHUB_REF_NAME"] + if tag != f"v{version}": + raise SystemExit(f"tag {tag!r} does not match package version v{version}") + print(f"Tag and package version agree: v{version}") + PY + + - name: Build sdist and wheel + run: | + python -m pip install --upgrade build twine + python -m build + python -m twine check dist/* + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/CHANGELOG.md b/CHANGELOG.md index cd42dcd..dc65010 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +- add PyPI packaging metadata and `pip install webvac` install path +- single-source the version from `webvac.__version__` +- add a tag-triggered PyPI release workflow using Trusted Publishing + ## 0.3.0 - 2026-08-18 - add an opt-in `--task vapt` workflow powered by De-Caffeinator diff --git a/README.md b/README.md index 4b9e51e..c23e467 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,19 @@ All application code lives in the installable `webvac/` package. See [`docs/STRU ## Installation +### From PyPI + +```bash +pip install webvac +python -m patchright install +``` + +That installs the `webvac` and `webvac-menu` console scripts. The PyPI package +contains the scraping core only; use a source checkout below if you also want +the `examples/`, `docs/`, or the `--task vapt` submodule. + +### From source + 1. Clone the repository. 2. Initialize the De-Caffeinator submodule (needed for `--task vapt`). 3. Create and activate a virtual environment. diff --git a/docs/RELEASE_CHECKLIST.md b/docs/RELEASE_CHECKLIST.md index 9e3b00a..e955316 100644 --- a/docs/RELEASE_CHECKLIST.md +++ b/docs/RELEASE_CHECKLIST.md @@ -125,7 +125,38 @@ git submodule status --- -## 10. Release-ready outcome +## 10. PyPI publish + +Publishing runs from the tag-driven `Release` workflow +(`.github/workflows/release.yml`) using PyPI Trusted Publishing, so no API token +is stored in the repository. + +One-time setup: + +- Create the `webvac` project on PyPI, or add a pending trusted publisher so the + first successful run creates it. +- Trusted publisher fields: owner `Shellghostt`, repository `WebVac`, workflow + `release.yml`. + +Before tagging: + +- `python -m build` and `python -m twine check dist/*` pass locally. +- `webvac/__init__.py` `__version__` equals the intended tag (`vX.Y.Z`). +- `CHANGELOG.md` has an entry for the version. + +Then publish: + +```bash +git tag v0.3.0 +git push origin v0.3.0 +``` + +The workflow refuses to publish if the tag and package version disagree. After +it completes, verify with `pip install webvac` in a clean environment. + +--- + +## 11. Release-ready outcome You are in good shape when: diff --git a/pyproject.toml b/pyproject.toml index a68c9a6..5c4e12a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,37 @@ [build-system] -requires = ["setuptools>=68", "wheel"] +requires = ["setuptools>=77", "wheel"] build-backend = "setuptools.build_meta" [project] name = "webvac" -version = "0.3.0" +dynamic = ["version"] description = "Asyncio dynamic web scraper with auth and an optional De-Caffeinator VAPT task." readme = "README.md" requires-python = ">=3.11" -license = { text = "MIT" } +license = "MIT" +license-files = ["LICENSE"] authors = [{ name = "Adityaaa" }] +keywords = [ + "scraping", + "crawler", + "browser-automation", + "playwright", + "patchright", + "asyncio", + "security", +] +classifiers = [ + "Development Status :: 4 - Beta", + "Environment :: Console", + "Intended Audience :: Developers", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Internet :: WWW/HTTP", + "Topic :: Security", +] dependencies = [ "patchright", "beautifulsoup4==4.12.3", @@ -27,10 +49,20 @@ dependencies = [ dev = ["pytest"] socks = ["aiohttp-socks"] +[project.urls] +Homepage = "https://github.com/Shellghostt/WebVac" +Repository = "https://github.com/Shellghostt/WebVac" +Issues = "https://github.com/Shellghostt/WebVac/issues" +Changelog = "https://github.com/Shellghostt/WebVac/blob/main/CHANGELOG.md" +Documentation = "https://github.com/Shellghostt/WebVac/blob/main/docs/README.md" + [project.scripts] webvac = "webvac.cli.scraper:main" webvac-menu = "webvac.cli.interactive:main" +[tool.setuptools.dynamic] +version = { attr = "webvac.__version__" } + [tool.setuptools.packages.find] where = ["."] include = ["webvac*"]