diff --git a/.github/workflows/ci_build_wheels.yaml b/.github/workflows/ci_build_wheels.yaml index 205d4be1..c7fca54a 100644 --- a/.github/workflows/ci_build_wheels.yaml +++ b/.github/workflows/ci_build_wheels.yaml @@ -55,5 +55,7 @@ jobs: needs: find-changes uses: ./.github/workflows/reusable_build_wheels.yaml secrets: inherit + permissions: + contents: write with: debug: ${{inputs.debug == true}} diff --git a/.github/workflows/release_wheels.yml b/.github/workflows/release_wheels.yml index 68eb5fa5..104fc054 100644 --- a/.github/workflows/release_wheels.yml +++ b/.github/workflows/release_wheels.yml @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -name: 'Build & release Python wheels' -run-name: 'Build Python wheels and release them on PyPI' +name: 'Build & publish Python wheels' +run-name: 'Build Python wheels and publish them on PyPI' on: release: @@ -25,23 +25,67 @@ on: description: 'Run with debugging options' type: boolean default: true + testpypi: + description: 'Release on TestPyPI' + type: boolean + default: true permissions: read-all +concurrency: + # Cancel any previously-started but still active runs on the same branch. + cancel-in-progress: true + group: ${{github.workflow}}-${{github.event.pull_request.number||github.ref}} + jobs: build-wheels: - name: Build and save wheels + name: Build wheels uses: ./.github/workflows/reusable_build_wheels.yaml secrets: inherit + permissions: + contents: write with: upload: true - debug: ${{inputs.debug}} + debug: ${{inputs.debug == true}} + + publish-to-testpypi: + if: inputs.testpypi == true + name: Publish wheels on TestPyPI + needs: build-wheels + runs-on: ubuntu-24.04 + timeout-minutes: 60 + permissions: + id-token: write + steps: + - name: Retrieve saved wheels + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 + with: + path: dist/ + pattern: python-wheels-* + merge-multiple: true + + - name: Publish wheels on TestPyPI + uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # release/v1 + with: + repository-url: https://test.pypi.org/legacy/ + user: __token__ + password: ${{secrets.TEST_PYPI_API_TOKEN}} + packages_dir: dist/ + verbose: ${{inputs.debug == true}} + print-hash: true - release-wheels: - name: Publish wheels + publish-to-pypi: + # Only publish on main/master branch. (This explicit test is necessary + # because in GHAs, you can't use "branches:" filters on release events.) + if: >- + (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master') + && inputs.testpypi != true + name: Publish wheels on PyPI needs: build-wheels runs-on: ubuntu-24.04 - timeout-minutes: 30 + timeout-minutes: 60 + permissions: + id-token: write steps: - name: Retrieve saved wheels uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 @@ -56,5 +100,6 @@ jobs: user: __token__ password: ${{secrets.PYPI_API_TOKEN}} packages_dir: dist/ - skip_existing: true - verbose: true + skip-existing: true + verbose: ${{inputs.debug == true}} + print-hash: true diff --git a/.github/workflows/reusable_build_wheels.yaml b/.github/workflows/reusable_build_wheels.yaml index 4f313812..b8fe6241 100644 --- a/.github/workflows/reusable_build_wheels.yaml +++ b/.github/workflows/reusable_build_wheels.yaml @@ -37,13 +37,14 @@ on: upload: description: 'Upload wheels to GitHub' type: boolean - default: false + default: true debug: description: 'Run with debugging options' type: boolean default: true -permissions: read-all +permissions: + contents: write jobs: build-wheels: @@ -60,6 +61,8 @@ jobs: {os: macos-15, arch: arm64}, {os: windows-2025, arch: AMD64}, ] + permissions: + contents: write steps: - name: Check out a copy of the git repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 @@ -80,7 +83,7 @@ jobs: run: | pip install -r requirements.txt pip install -r dev-requirements.txt - pip install cibuildwheel==2.23.3 + pip install cibuildwheel==2.23.3 twine==6.1.0 check-wheel-contents==0.6.2 - if: startsWith(matrix.conf.os, 'macos') name: Set CMake MACOSX_DEPLOYMENT_TARGET value on MacOS @@ -89,19 +92,6 @@ jobs: os=${{matrix.conf.os}} echo MACOSX_DEPLOYMENT_TARGET=${os: -2} >> "$GITHUB_ENV" - - if: startsWith(matrix.conf.os, 'ubuntu') - name: Determine the number of threads to use (Linux) - run: echo "num_threads=$(( $(nproc) - 1 ))" >> "$GITHUB_ENV" - - - if: startsWith(matrix.conf.os, 'macos') - name: Determine the number of threads to use (MacOS) - run: echo "num_threads=$(( $(sysctl -n hw.ncpu) - 1 ))" >> "$GITHUB_ENV" - - - if: startsWith(matrix.conf.os, 'win') - name: Determine the number of threads to use (Windows) - shell: bash - run: echo "num_threads=$(( NUMBER_OF_PROCESSORS - 1 ))" >> "$GITHUB_ENV" - - name: Build and test wheels env: # Note: additional cibuildwheel settings are in pyproject.toml. @@ -110,11 +100,19 @@ jobs: CIBW_BUILD_VERBOSITY: ${{inputs.debug && 1 || ''}} # Color codes make the raw logs hard to read. (CMake uses CLICOLOR.) CLICOLOR: ${{inputs.debug && 0 || ''}} - CMAKE_BUILD_PARALLEL_LEVEL: ${{env.num_threads}} run: | cibuildwheel --output-dir wheelhouse - - if: inputs.upload != false + - name: Run twine check + run: | + twine check --strict wheelhouse/* + + - name: Check wheel contents + run: | + check-wheel-contents wheelhouse/* + + # Only take the time to save the wheels if doing a release. + - if: inputs.upload == true name: Upload wheels to GitHub uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: diff --git a/pyproject.toml b/pyproject.toml index 1104e603..17bf7a89 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,3 +27,7 @@ repair-wheel-command = "delocate-listdeps {wheel} && delocate-wheel --verbose -- manylinux-x86_64-image = "manylinux2014" manylinux-i686-image = "manylinux2014" skip = "*musllinux*" + +[tool.check-wheel-contents] +# See https://github.com/jwodder/check-wheel-contents for a list of codes. +ignore = "W009,W010"