From 69467dfedc567a108fdc6632e4bde30bb3d49873 Mon Sep 17 00:00:00 2001 From: Rok Mihevc Date: Fri, 6 Nov 2026 15:24:54 +0100 Subject: [PATCH 1/8] MAINT: read the package version from __init__.py The version was in both pyproject.toml and src/benchx/__init__.py. A release needs one value, since the tag, the packages and the version recorded in results must all agree. --- pyproject.toml | 5 ++++- uv.lock | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index eea6e24..0e76669 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "benchx" -version = "0.1.0" +dynamic = ["version"] description = "BenchX: a flexible and powerful benchmarking framework" license = "Apache-2.0" license-files = ["LICENSE"] @@ -33,6 +33,9 @@ bx = "benchx.cli:main" requires = ["hatchling>=1.26"] build-backend = "hatchling.build" +[tool.hatch.version] +path = "src/benchx/__init__.py" + [tool.hatch.build.targets.wheel] packages = ["src/benchx"] diff --git a/uv.lock b/uv.lock index b2c03f4..65762fc 100644 --- a/uv.lock +++ b/uv.lock @@ -35,7 +35,6 @@ wheels = [ [[package]] name = "benchx" -version = "0.1.0" source = { editable = "." } dependencies = [ { name = "jsonpointer" }, From e7ef2b32844baccbd8fb1558f7849bba257bd3c3 Mon Sep 17 00:00:00 2001 From: Rok Mihevc Date: Fri, 6 Nov 2026 15:24:54 +0100 Subject: [PATCH 2/8] MAINT: name the runner benchx, not benchx-prototype The name is written into every result document, so change it before the first release. --- src/benchx/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/benchx/runner.py b/src/benchx/runner.py index 7e49039..95507d5 100644 --- a/src/benchx/runner.py +++ b/src/benchx/runner.py @@ -17,7 +17,7 @@ from .adapters.base import Unsupported, no_cases from .core import Refusal, Rejected -RUNNER = {"name": "benchx-prototype", "version": __version__} +RUNNER = {"name": "benchx", "version": __version__} # The runner's own probe: one condition measurement per attempt (schema ยง4.4). PROBE_PRODUCER = {"name": "benchx/runner-probe", "version": __version__, "mapping_version": "benchx-probe/v1"} LOAD = {"name": "load-average", "unit": "1"} From 42994d772167c5fbc96e3b61db9f7da3595b7b52 Mon Sep 17 00:00:00 2001 From: Rok Mihevc Date: Fri, 6 Nov 2026 15:24:54 +0100 Subject: [PATCH 3/8] DOC: add install instructions; make the UC-04 link absolute This page is the package's description on PyPI, where a relative link does not resolve. --- docs/benchx.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/benchx.md b/docs/benchx.md index 9f3c56c..dedc5c3 100644 --- a/docs/benchx.md +++ b/docs/benchx.md @@ -127,7 +127,7 @@ is a runnable walk-through. Environments that cannot share a process, such as two venvs with different numpy versions, are measured by separate `bx bench` calls that share a `--run-key`; `--label NAME=VALUE`, `--round N` and `--slot K` place each call in the session, and `bx compare --run KEY --profile environments ---label NAME --baseline VALUE` compares the sides ([UC-04](use-cases/UC-04-cross-env.md)). +--label NAME --baseline VALUE` compares the sides ([UC-04](https://benchx-dev.github.io/benchx/use-cases/UC-04-cross-env/)). `examples/numpy-venvs` in [benchx_examples](https://github.com/benchx-dev/benchx_examples) is the worked example, with a shell script that drives it. @@ -214,6 +214,13 @@ every result is pyperf. Results also record the installed project's version store: the ad hoc path. Condition measurements (`measurement.kind: condition`) are not compared, and deterministic quantities are deferred. +## Install + +```console +$ pip install benchx +$ conda install -c BenchX -c conda-forge benchx # its dependencies are on conda-forge +``` + ## Run it ```console From 7e1d6b8cde0e6d3a809b2b0001250e11a2c52fd4 Mon Sep 17 00:00:00 2001 From: Rok Mihevc Date: Fri, 6 Nov 2026 15:24:54 +0100 Subject: [PATCH 4/8] CI: publish releases to PyPI and anaconda.org A v* tag builds and tests the sdist, the wheel and a noarch conda package, then uploads to PyPI through trusted publishing and to the BenchX channel on anaconda.org, and creates the GitHub release. A pull request that changes the packaging runs the build jobs only. --- .github/workflows/release.yml | 180 ++++++++++++++++++++++++++++++++++ conda/recipe.yaml | 63 ++++++++++++ 2 files changed, 243 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 conda/recipe.yaml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..0e2ca78 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,180 @@ +name: release + +# Publishes benchx to PyPI and anaconda.org, and creates the GitHub release. To release, set +# __version__ in src/benchx/__init__.py, merge that, and push the tag v from main: +# +# v0.1.0 goes to PyPI and to the main label on anaconda.org +# v0.1.0rc1 goes to PyPI as a pre-release and to the rc label on anaconda.org +# +# Both packages are built and tested before anything is uploaded. PyPI versions cannot be +# reused, so PyPI goes first; if the anaconda.org upload fails, re-run that job. +# +# A pull request that changes the packaging runs the two build jobs and uploads nothing. +# +# This needs, on GitHub, the environments below with their required reviewers, the secret +# ANACONDA_API_KEY in the anaconda environment, and on PyPI a trusted publisher for this file +# and the pypi environment. The actions are pinned to commits since they handle the uploads. + +on: + push: + tags: ["v*"] + pull_request: + branches: [main] + paths: + - ".github/workflows/release.yml" + - "conda/**" + - "pyproject.toml" + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.version.outputs.version }} + prerelease: ${{ steps.version.outputs.prerelease }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3 + + - name: Build the sdist, and the wheel from it + run: uv build + + - name: Read the version from the sdist + id: version + run: | + version=$(basename dist/benchx-*.tar.gz .tar.gz) + version=${version#benchx-} + echo "version=$version" >> "$GITHUB_OUTPUT" + if [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "prerelease=false" >> "$GITHUB_OUTPUT" + else + echo "prerelease=true" >> "$GITHUB_OUTPUT" + fi + + - name: Check that the tag names this version + if: github.ref_type == 'tag' + env: + TAG: ${{ github.ref_name }} + VERSION: ${{ steps.version.outputs.version }} + run: | + if [ "$TAG" != "v$VERSION" ]; then + echo "::error::tag $TAG does not match the package version $VERSION" + exit 1 + fi + + - name: Check the package metadata + run: uvx twine check --strict dist/* + + - name: Install the wheel into a clean environment and test it + run: | + uv venv --python 3.13 "$RUNNER_TEMP/venv" + source "$RUNNER_TEMP/venv/bin/activate" + uv pip install "$(ls dist/*.whl)[test]" + # Away from the checkout, so that nothing can import it instead of the installed package. + cd "$RUNNER_TEMP" + bx --help + python -m pytest --pyargs benchx -ra + + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: dist + path: dist/ + if-no-files-found: error + + conda: + needs: build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + name: dist + path: dist + + - uses: mamba-org/setup-micromamba@f457c30a868e4760d3a6fcea5f25dc655b8edf39 # v3.2.1 + with: + environment-name: rattler-build + create-args: -c conda-forge rattler-build=0.80.0 + + - name: Build and test the conda package from the sdist + shell: bash -el {0} + env: + BENCHX_VERSION: ${{ needs.build.outputs.version }} + run: | + export BENCHX_SDIST="$PWD/dist/benchx-$BENCHX_VERSION.tar.gz" + rattler-build build --recipe conda/recipe.yaml --output-dir conda-output -c conda-forge + + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: conda + path: conda-output/noarch/*.conda + if-no-files-found: error + + publish-pypi: + needs: [build, conda] + # Also what keeps the jobs after this one off pull requests and forks: they need this one. + if: github.repository == 'benchx-dev/benchx' && github.ref_type == 'tag' + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/project/benchx/${{ needs.build.outputs.version }}/ + permissions: + id-token: write + steps: + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + name: dist + path: dist + + - uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3 + + publish-conda: + needs: [build, publish-pypi] + runs-on: ubuntu-latest + environment: + name: anaconda + url: https://anaconda.org/BenchX/benchx + steps: + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + name: conda + path: conda-packages + + - uses: mamba-org/setup-micromamba@f457c30a868e4760d3a6fcea5f25dc655b8edf39 # v3.2.1 + with: + environment-name: rattler-build + create-args: -c conda-forge rattler-build=0.80.0 + + - name: Upload to anaconda.org + shell: bash -el {0} + env: + ANACONDA_API_KEY: ${{ secrets.ANACONDA_API_KEY }} + LABEL: ${{ needs.build.outputs.prerelease == 'true' && 'rc' || 'main' }} + run: rattler-build upload anaconda --owner BenchX --channel "$LABEL" conda-packages/*.conda + + github-release: + needs: [build, publish-pypi, publish-conda] + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + path: release-files + merge-multiple: true + + - name: Create the release + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + TAG: ${{ github.ref_name }} + PRERELEASE: ${{ needs.build.outputs.prerelease }} + run: gh release create "$TAG" release-files/* --verify-tag --generate-notes --prerelease="$PRERELEASE" diff --git a/conda/recipe.yaml b/conda/recipe.yaml new file mode 100644 index 0000000..01181fa --- /dev/null +++ b/conda/recipe.yaml @@ -0,0 +1,63 @@ +# Built by .github/workflows/release.yml from the sdist, so that conda and PyPI ship the +# same source. To build it by hand, after `uv build`: +# +# BENCHX_VERSION= BENCHX_SDIST=$PWD/dist/benchx-.tar.gz \ +# rattler-build build --recipe conda/recipe.yaml -c conda-forge + +context: + version: ${{ env.get("BENCHX_VERSION") }} + python_min: "3.11" + +package: + name: benchx + version: ${{ version }} + +source: + path: ${{ env.get("BENCHX_SDIST") }} + +build: + number: 0 + noarch: python + script: python -m pip install . --no-deps --no-build-isolation -vv + python: + entry_points: + - bx = benchx.cli:main + +requirements: + host: + - python ${{ python_min }}.* + - pip + - hatchling >=1.26 + run: + - python >=${{ python_min }} + - pyarrow >=19 + # conda-forge's name for jsonschema[format-nongpl] + - jsonschema-with-format-nongpl >=4.18 + - jsonpointer >=2.0 + - referencing + - rfc8785 + +tests: + - python: + imports: + - benchx + - benchx.cli + pip_check: true + python_version: ${{ python_min }}.* + - requirements: + run: + - python ${{ python_min }}.* + - pytest + - pyperf + - asv_runner + script: + - bx --help + - python -m pytest --pyargs benchx -ra + +about: + homepage: https://github.com/benchx-dev/benchx + repository: https://github.com/benchx-dev/benchx + documentation: https://benchx-dev.github.io/benchx/benchx/ + summary: "BenchX: a flexible and powerful benchmarking framework" + license: Apache-2.0 + license_file: LICENSE From fb70abe5198ca3de4a572eda25c768f8b56a0e61 Mon Sep 17 00:00:00 2001 From: Rok Mihevc Date: Fri, 6 Nov 2026 17:08:44 +0100 Subject: [PATCH 5/8] CI: publish to PyPI only for now PyPI's trusted publishing needs no stored token, while uploading to anaconda.org would need a long-lived one. Keep building and testing the conda package, which publishes nothing: it tests the oldest supported Python, and the recipe can seed a conda-forge feedstock. --- .github/workflows/release.yml | 53 +++++++---------------------------- conda/recipe.yaml | 4 +-- docs/benchx.md | 1 - 3 files changed, 12 insertions(+), 46 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0e2ca78..2b945d3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,19 +1,16 @@ name: release -# Publishes benchx to PyPI and anaconda.org, and creates the GitHub release. To release, set -# __version__ in src/benchx/__init__.py, merge that, and push the tag v from main: +# Publishes benchx to PyPI and creates the GitHub release, when the tag v is pushed. +# docs/releasing.md is the checklist. A tag such as v0.1.0rc1 makes a pre-release. # -# v0.1.0 goes to PyPI and to the main label on anaconda.org -# v0.1.0rc1 goes to PyPI as a pre-release and to the rc label on anaconda.org -# -# Both packages are built and tested before anything is uploaded. PyPI versions cannot be -# reused, so PyPI goes first; if the anaconda.org upload fails, re-run that job. +# The conda job publishes nothing: it checks that the package still builds for conda, and tests +# it on the oldest supported Python. Everything is tested before anything is uploaded. # # A pull request that changes the packaging runs the two build jobs and uploads nothing. # -# This needs, on GitHub, the environments below with their required reviewers, the secret -# ANACONDA_API_KEY in the anaconda environment, and on PyPI a trusted publisher for this file -# and the pypi environment. The actions are pinned to commits since they handle the uploads. +# This needs, on GitHub, the pypi environment with its required reviewers, and on PyPI a trusted +# publisher for this file and that environment. The actions are pinned to commits since they +# handle the uploads. on: push: @@ -112,15 +109,9 @@ jobs: export BENCHX_SDIST="$PWD/dist/benchx-$BENCHX_VERSION.tar.gz" rattler-build build --recipe conda/recipe.yaml --output-dir conda-output -c conda-forge - - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 - with: - name: conda - path: conda-output/noarch/*.conda - if-no-files-found: error - publish-pypi: needs: [build, conda] - # Also what keeps the jobs after this one off pull requests and forks: they need this one. + # Also what keeps the job after this one off pull requests and forks: it needs this one. if: github.repository == 'benchx-dev/benchx' && github.ref_type == 'tag' runs-on: ubuntu-latest environment: @@ -136,40 +127,16 @@ jobs: - uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3 - publish-conda: - needs: [build, publish-pypi] - runs-on: ubuntu-latest - environment: - name: anaconda - url: https://anaconda.org/BenchX/benchx - steps: - - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 - with: - name: conda - path: conda-packages - - - uses: mamba-org/setup-micromamba@f457c30a868e4760d3a6fcea5f25dc655b8edf39 # v3.2.1 - with: - environment-name: rattler-build - create-args: -c conda-forge rattler-build=0.80.0 - - - name: Upload to anaconda.org - shell: bash -el {0} - env: - ANACONDA_API_KEY: ${{ secrets.ANACONDA_API_KEY }} - LABEL: ${{ needs.build.outputs.prerelease == 'true' && 'rc' || 'main' }} - run: rattler-build upload anaconda --owner BenchX --channel "$LABEL" conda-packages/*.conda - github-release: - needs: [build, publish-pypi, publish-conda] + needs: [build, publish-pypi] runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: + name: dist path: release-files - merge-multiple: true - name: Create the release env: diff --git a/conda/recipe.yaml b/conda/recipe.yaml index 01181fa..b942e2b 100644 --- a/conda/recipe.yaml +++ b/conda/recipe.yaml @@ -1,5 +1,5 @@ -# Built by .github/workflows/release.yml from the sdist, so that conda and PyPI ship the -# same source. To build it by hand, after `uv build`: +# Built and tested from the sdist by .github/workflows/release.yml, which does not publish it. +# To build it by hand, after `uv build`: # # BENCHX_VERSION= BENCHX_SDIST=$PWD/dist/benchx-.tar.gz \ # rattler-build build --recipe conda/recipe.yaml -c conda-forge diff --git a/docs/benchx.md b/docs/benchx.md index dedc5c3..45c62c2 100644 --- a/docs/benchx.md +++ b/docs/benchx.md @@ -218,7 +218,6 @@ every result is pyperf. Results also record the installed project's version ```console $ pip install benchx -$ conda install -c BenchX -c conda-forge benchx # its dependencies are on conda-forge ``` ## Run it From 4189102f84f11bc42894fcc6e3742277243e125c Mon Sep 17 00:00:00 2001 From: Rok Mihevc Date: Fri, 6 Nov 2026 17:08:44 +0100 Subject: [PATCH 6/8] DOC: add a release checklist --- docs/releasing.md | 60 +++++++++++++++++++++++++++++++++++++++++++++++ zensical.toml | 1 + 2 files changed, 61 insertions(+) create mode 100644 docs/releasing.md diff --git a/docs/releasing.md b/docs/releasing.md new file mode 100644 index 0000000..5f775df --- /dev/null +++ b/docs/releasing.md @@ -0,0 +1,60 @@ +# Releasing benchx + +Pushing a tag `v` runs `.github/workflows/release.yml`. It builds and tests the +package, waits for approval, publishes to PyPI, and creates the GitHub release. Below, +`upstream` is your remote for `benchx-dev/benchx`, and `0.1.0` stands for the version. + +## Checklist + +1. **Check CI.** The release workflow runs its own tests, but it does not look at the other + workflows, so check that the latest commit on `main` is green. +2. **Prepare the release in a pull request, and merge it.** + - Set `__version__` in `src/benchx/__init__.py`; `pyproject.toml` reads it from there. + - Update `CHANGELOG.md`, including the list of contributors. +3. **Tag the merged commit and push the tag.** The tag must be `v` plus exactly the version in + `__version__`, or the workflow stops before uploading anything. + + ```console + $ git fetch upstream + $ git tag -a v0.1.0 -m "benchx 0.1.0" upstream/main + $ git push upstream v0.1.0 + ``` + +4. **Approve the `publish-pypi` job** when the + [workflow run](https://github.com/benchx-dev/benchx/actions/workflows/release.yml) asks. Any + required reviewer of the `pypi` environment can approve it, including whoever pushed the tag. +5. **Check the result.** The run should be green, with the version on + [PyPI](https://pypi.org/project/benchx/) and in the + [GitHub releases](https://github.com/benchx-dev/benchx/releases). +6. **Test the install in a new environment.** Activate it, because the tests start benchmarks + with whichever `python` is on `PATH`. + + ```console + $ python -m venv venv && source venv/bin/activate + $ pip install 'benchx[test]==0.1.0' + $ bx --help + $ python -m pytest --pyargs benchx + ``` + +## Pre-releases + +A version such as `0.1.0rc1`, tagged `v0.1.0rc1`, follows the same steps. It is marked as a +pre-release on GitHub, and `pip install benchx` skips it unless the version is named or +`--pre` is given. + +## If something fails + +- **Before the upload:** nothing is published. Delete the tag, fix the problem, and tag again: + + ```console + $ git push upstream --delete v0.1.0 + $ git tag -d v0.1.0 + ``` + +- **During the upload to PyPI:** check the [PyPI project](https://pypi.org/project/benchx/) + first. If the version is not there, re-run the failed job. +- **After the upload to PyPI, in `github-release`:** the package is published, so re-run the + failed job. +- **A published version is wrong:** PyPI does not allow a version to be uploaded again, even + after it is deleted, so release a new version. Yanking the bad one on PyPI stops new installs + from picking it up by default. diff --git a/zensical.toml b/zensical.toml index a3dc99f..fe06bbc 100644 --- a/zensical.toml +++ b/zensical.toml @@ -73,6 +73,7 @@ nav = [ { "One-off benchmarking" = "user_stories/one-off.md" }, ] }, { "benchx" = "benchx.md" }, + { "Releasing" = "releasing.md" }, ] [project.validation] From 216465e5e3b0c6bb15c05c6e9c16109b130bc8aa Mon Sep 17 00:00:00 2001 From: Rok Mihevc Date: Fri, 6 Nov 2026 17:16:05 +0100 Subject: [PATCH 7/8] CI: leave conda packages to conda-forge Conda packages will come from a feedstock on conda-forge, which has its own recipe and follows the releases on PyPI. Remove the recipe and the conda job here: they would duplicate it, and a conda failure should not hold up a PyPI release. Add the feedstock update to the checklist. --- .github/workflows/release.yml | 35 +++---------------- conda/recipe.yaml | 63 ----------------------------------- docs/releasing.md | 4 +++ 3 files changed, 8 insertions(+), 94 deletions(-) delete mode 100644 conda/recipe.yaml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2b945d3..10e4895 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,10 +3,10 @@ name: release # Publishes benchx to PyPI and creates the GitHub release, when the tag v is pushed. # docs/releasing.md is the checklist. A tag such as v0.1.0rc1 makes a pre-release. # -# The conda job publishes nothing: it checks that the package still builds for conda, and tests -# it on the oldest supported Python. Everything is tested before anything is uploaded. +# The package is tested before anything is uploaded. Conda packages are not built here: they +# come from the benchx feedstock on conda-forge, which follows the releases on PyPI. # -# A pull request that changes the packaging runs the two build jobs and uploads nothing. +# A pull request that changes the packaging runs the build job and uploads nothing. # # This needs, on GitHub, the pypi environment with its required reviewers, and on PyPI a trusted # publisher for this file and that environment. The actions are pinned to commits since they @@ -19,7 +19,6 @@ on: branches: [main] paths: - ".github/workflows/release.yml" - - "conda/**" - "pyproject.toml" permissions: @@ -83,34 +82,8 @@ jobs: path: dist/ if-no-files-found: error - conda: - needs: build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 - with: - name: dist - path: dist - - - uses: mamba-org/setup-micromamba@f457c30a868e4760d3a6fcea5f25dc655b8edf39 # v3.2.1 - with: - environment-name: rattler-build - create-args: -c conda-forge rattler-build=0.80.0 - - - name: Build and test the conda package from the sdist - shell: bash -el {0} - env: - BENCHX_VERSION: ${{ needs.build.outputs.version }} - run: | - export BENCHX_SDIST="$PWD/dist/benchx-$BENCHX_VERSION.tar.gz" - rattler-build build --recipe conda/recipe.yaml --output-dir conda-output -c conda-forge - publish-pypi: - needs: [build, conda] + needs: build # Also what keeps the job after this one off pull requests and forks: it needs this one. if: github.repository == 'benchx-dev/benchx' && github.ref_type == 'tag' runs-on: ubuntu-latest diff --git a/conda/recipe.yaml b/conda/recipe.yaml deleted file mode 100644 index b942e2b..0000000 --- a/conda/recipe.yaml +++ /dev/null @@ -1,63 +0,0 @@ -# Built and tested from the sdist by .github/workflows/release.yml, which does not publish it. -# To build it by hand, after `uv build`: -# -# BENCHX_VERSION= BENCHX_SDIST=$PWD/dist/benchx-.tar.gz \ -# rattler-build build --recipe conda/recipe.yaml -c conda-forge - -context: - version: ${{ env.get("BENCHX_VERSION") }} - python_min: "3.11" - -package: - name: benchx - version: ${{ version }} - -source: - path: ${{ env.get("BENCHX_SDIST") }} - -build: - number: 0 - noarch: python - script: python -m pip install . --no-deps --no-build-isolation -vv - python: - entry_points: - - bx = benchx.cli:main - -requirements: - host: - - python ${{ python_min }}.* - - pip - - hatchling >=1.26 - run: - - python >=${{ python_min }} - - pyarrow >=19 - # conda-forge's name for jsonschema[format-nongpl] - - jsonschema-with-format-nongpl >=4.18 - - jsonpointer >=2.0 - - referencing - - rfc8785 - -tests: - - python: - imports: - - benchx - - benchx.cli - pip_check: true - python_version: ${{ python_min }}.* - - requirements: - run: - - python ${{ python_min }}.* - - pytest - - pyperf - - asv_runner - script: - - bx --help - - python -m pytest --pyargs benchx -ra - -about: - homepage: https://github.com/benchx-dev/benchx - repository: https://github.com/benchx-dev/benchx - documentation: https://benchx-dev.github.io/benchx/benchx/ - summary: "BenchX: a flexible and powerful benchmarking framework" - license: Apache-2.0 - license_file: LICENSE diff --git a/docs/releasing.md b/docs/releasing.md index 5f775df..c119def 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -36,6 +36,10 @@ package, waits for approval, publishes to PyPI, and creates the GitHub release. $ python -m pytest --pyargs benchx ``` +7. **Merge the conda-forge update.** Conda packages come from the benchx feedstock on + conda-forge, not from this repository. Once that feedstock exists, conda-forge's bot opens a + pull request on it after a new version reaches PyPI; review and merge that pull request. + ## Pre-releases A version such as `0.1.0rc1`, tagged `v0.1.0rc1`, follows the same steps. It is marked as a From eac2c66b9d86d47e8df406608c0bd8fda040734b Mon Sep 17 00:00:00 2001 From: Rok Mihevc Date: Fri, 6 Nov 2026 17:45:32 +0100 Subject: [PATCH 8/8] DOC: add the .dev0 bump to the release checklist; check version changes in CI Start the next development version after a final release, so that results from main do not claim to come from the release. Say that a second person has to approve, since the pypi environment prevents self-review. Run the build job on pull requests that change the version. --- .github/workflows/release.yml | 4 +++- docs/releasing.md | 12 ++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 10e4895..6771674 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,7 +6,8 @@ name: release # The package is tested before anything is uploaded. Conda packages are not built here: they # come from the benchx feedstock on conda-forge, which follows the releases on PyPI. # -# A pull request that changes the packaging runs the build job and uploads nothing. +# Only a tag publishes. A pull request that changes the packaging or the version runs the build +# job and uploads nothing. # # This needs, on GitHub, the pypi environment with its required reviewers, and on PyPI a trusted # publisher for this file and that environment. The actions are pinned to commits since they @@ -20,6 +21,7 @@ on: paths: - ".github/workflows/release.yml" - "pyproject.toml" + - "src/benchx/__init__.py" permissions: contents: read diff --git a/docs/releasing.md b/docs/releasing.md index c119def..93c7c98 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -20,9 +20,10 @@ package, waits for approval, publishes to PyPI, and creates the GitHub release. $ git push upstream v0.1.0 ``` -4. **Approve the `publish-pypi` job** when the - [workflow run](https://github.com/benchx-dev/benchx/actions/workflows/release.yml) asks. Any - required reviewer of the `pypi` environment can approve it, including whoever pushed the tag. +4. **Approve the `publish-pypi` job.** Once the tests pass, the + [workflow run](https://github.com/benchx-dev/benchx/actions/workflows/release.yml) waits and + shows a "Review deployments" button. A required reviewer of the `pypi` environment other than + whoever pushed the tag has to approve it, so a release takes two people. 5. **Check the result.** The run should be green, with the version on [PyPI](https://pypi.org/project/benchx/) and in the [GitHub releases](https://github.com/benchx-dev/benchx/releases). @@ -39,10 +40,13 @@ package, waits for approval, publishes to PyPI, and creates the GitHub release. 7. **Merge the conda-forge update.** Conda packages come from the benchx feedstock on conda-forge, not from this repository. Once that feedstock exists, conda-forge's bot opens a pull request on it after a new version reaches PyPI; review and merge that pull request. +8. **Start the next development version.** In a pull request, set `__version__` to the next + version with a `.dev0` suffix: after `0.1.0`, that is `0.2.0.dev0`. Results record this version, + so without this step, results from `main` would claim to come from the release. ## Pre-releases -A version such as `0.1.0rc1`, tagged `v0.1.0rc1`, follows the same steps. It is marked as a +A version such as `0.1.0rc1`, tagged `v0.1.0rc1`, follows steps 1 to 6. It is marked as a pre-release on GitHub, and `pip install benchx` skips it unless the version is named or `--pre` is given.