diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 53d3f62..016cf04 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,9 +2,7 @@ name: Release on: push: - branches: [main] - paths: - - "pyproject.toml" + tags: ["v*"] workflow_dispatch: @@ -12,36 +10,28 @@ jobs: release: runs-on: ubuntu-latest + permissions: + # Required for PyPI Trusted Publishing (OIDC), so no API token is stored. + id-token: write + # Required to create the GitHub Release. + contents: write + steps: - uses: actions/checkout@v7 + with: + # hatch-vcs derives the version from the git tag, so it needs the + # full history and tags, not a shallow clone. + fetch-depth: 0 - uses: ./.github/workflows/util/setup_python - - name: Determine version - id: version - run: echo "version=$(uv version --short)" >> "$GITHUB_OUTPUT" - - - name: Check if version is already released - id: check - env: - VERSION: ${{ steps.version.outputs.version }} - run: | - code=$(curl -fsS -o /dev/null -w "%{http_code}" \ - "https://pypi.org/pypi/shpyx/${VERSION}/json" || true) - if [ "$code" = "200" ]; then - echo "shpyx ${VERSION} is already on PyPI, skipping release." - echo "publish=false" >> "$GITHUB_OUTPUT" - else - echo "shpyx ${VERSION} is new, releasing." - echo "publish=true" >> "$GITHUB_OUTPUT" - fi - - name: Build - if: steps.check.outputs.publish == 'true' run: uv build - - name: Publish - if: steps.check.outputs.publish == 'true' - env: - UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }} - run: uv publish + - name: Publish to PyPI + run: uv publish --trusted-publishing always + + - name: Create GitHub Release + uses: softprops/action-gh-release@v3 + with: + generate_release_notes: true diff --git a/README.md b/README.md index f575caf..faceebb 100644 --- a/README.md +++ b/README.md @@ -178,38 +178,41 @@ Other 3rd-party libraries for running shell commands in Python: To contribute simply open a PR with your changes. -Tests, linters and type checks are run in CI through GitHub Actions. +All checks (Linters, type checks and tests) automatically run in CI through GitHub Actions. ### Running checks locally -To run checks locally, start by installing all the development dependencies: +Local development is done with [uv](https://docs.astral.sh/uv/getting-started/installation/). +Start by installing all the development dependencies: ```shell uv sync ``` To run the linters use `pre-commit`: - ```shell pre-commit run -a ``` To run the unit tests use `pytest`: - ```shell pytest -c tests/pytest.ini tests ``` -To run type checks use `mypy`: - +To run type checks use `mypy` or `ty` (both are run in CI): ```shell mypy --config-file linters/mypy.toml src tests +ty check --config-file linters/ty.toml src tests ``` -and `ty`: +### Releasing +The package version is derived from the git tag (via `hatch-vcs`), so there is nothing to bump in +`pyproject.toml`. To release a new version, push a `v`-prefixed tag from `main`: ```shell -ty check --config-file linters/ty.toml src tests +git tag v0.0.37 +git push origin v0.0.37 ``` -To trigger a deployment of a new version upon merge, bump the version number in `pyproject.toml`. +This triggers the `Release` workflow, which builds the package, publishes it to PyPI using Trusted +Publishing (OIDC, no stored token), and creates a GitHub Release with auto-generated notes. diff --git a/linters/cspell/words.txt b/linters/cspell/words.txt index a65c054..502735f 100644 --- a/linters/cspell/words.txt +++ b/linters/cspell/words.txt @@ -33,3 +33,4 @@ pathlib anyio multibyte haia +softprops diff --git a/pyproject.toml b/pyproject.toml index adf7ff6..4501afc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,21 @@ [build-system] build-backend = "hatchling.build" -requires = ["hatchling"] +requires = ["hatchling", "hatch-vcs"] + +[dependency-groups] +dev = [ + "mypy==2.2.0", + "pre-commit==4.6.0", + "pytest-cov==7.1.0", + "pytest-mock==3.15.1", + "pytest==9.1.1", + "ruff==0.15.21", + "ty==0.0.58", +] [project] name = "shpyx" -version = "0.0.36" +dynamic = ["version"] description = "Run shell commands in Python" authors = [{name = "Yossi Rozantsev"}] license = {text = "MIT"} @@ -19,20 +30,14 @@ classifiers = [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", ] -dependencies = [ - "mypy==2.2.0", - "pre-commit==4.6.0", - "pytest-cov==7.1.0", - "pytest-mock==3.15.1", - "pytest==9.1.1", - "ruff==0.15.21", - "ty==0.0.58", -] [project.urls] homepage = "https://github.com/Apakottur/shpyx" repository = "https://github.com/Apakottur/shpyx" documentation = "https://github.com/Apakottur/shpyx" +[tool.hatch.version] +source = "vcs" + [tool.uv] package = true diff --git a/uv.lock b/uv.lock index 562a6aa..af28884 100644 --- a/uv.lock +++ b/uv.lock @@ -590,9 +590,10 @@ wheels = [ [[package]] name = "shpyx" -version = "0.0.36" source = { editable = "." } -dependencies = [ + +[package.dev-dependencies] +dev = [ { name = "mypy" }, { name = "pre-commit" }, { name = "pytest" }, @@ -603,7 +604,9 @@ dependencies = [ ] [package.metadata] -requires-dist = [ + +[package.metadata.requires-dev] +dev = [ { name = "mypy", specifier = "==2.2.0" }, { name = "pre-commit", specifier = "==4.6.0" }, { name = "pytest", specifier = "==9.1.1" },