Skip to content

docs: fix broken URL (#657) #52

docs: fix broken URL (#657)

docs: fix broken URL (#657) #52

Workflow file for this run

# Single workflow: release-please proposes/cuts releases, and the same run
# builds + publishes wheels once a release is actually created.
#
# Previously release-please.yml and this file were separate workflows, with
# this one triggered on `release: created`. That event never fired in
# practice: release-please-action creates the GitHub Release using the
# default GITHUB_TOKEN, and GitHub deliberately does not cascade events
# triggered by that token to *other* workflows (anti-recursion protection).
# Confirmed the hard way shipping v1.4.0 (2026-08-23): release-please's PR
# merged, the tag+release were created, and release.yml simply never ran --
# required a manual `workflow_dispatch` to publish, which in turn skipped
# `upload_pyodide_asset` (gated on `github.event_name == 'release'`),
# leaving the release with no wasm asset until a manual backfill.
#
# Fix: merge both into one workflow so the build/publish jobs are downstream
# jobs of release-please's own job in the *same* run, gated on its
# `release_created`/`tag_name` outputs -- this sidesteps the cross-workflow
# trigger restriction entirely, since nothing needs to fire a second time.
# This is release-please-action's own documented pattern for this problem.
#
# `workflow_dispatch` is kept for manual rebuilds (e.g. to regenerate
# artifacts) -- on that trigger the release-please job is skipped and
# `verify_version` skips its tag-match check (no fresh tag to check
# against).
#
# Uses OIDC trusted publishing for PyPI -- no stored PyPI token required.
# macOS uses macos-14 (arm64); cibuildwheel cross-compiles x86_64 as well
# (see [tool.cibuildwheel.macos] archs in pyproject.toml).
# Check for latest cibuildwheel: https://github.com/pypa/cibuildwheel/releases
name: Release
on:
push:
branches: [main]
workflow_dispatch:
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
permissions:
contents: write
pull-requests: write
jobs:
release-please:
name: Release Please
if: github.event_name == 'push'
runs-on: ubuntu-latest
outputs:
release_created: ${{ steps.release.outputs.release_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
steps:
- uses: googleapis/release-please-action@v5
id: release
with:
config-file: .github/release-please-config.json
manifest-file: .github/.release-please-manifest.json
verify_version:
name: Verify tag matches package version
needs: release-please
# Runs on workflow_dispatch (manual rebuild) or on a push that release-please
# just turned into a real release. `always()` is required here because the
# release-please job is skipped on workflow_dispatch, and a skipped `needs`
# job would otherwise auto-skip this one under the default `if: success()`.
if: >
always() &&
(github.event_name == 'workflow_dispatch' ||
(needs.release-please.result == 'success' && needs.release-please.outputs.release_created == 'true'))
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Check version
# Skip on manual workflow_dispatch runs (no fresh tag to check against)
if: needs.release-please.outputs.release_created == 'true'
run: |
TAG="${{ needs.release-please.outputs.tag_name }}"
TAG="${TAG#v}"
PKG=$(python3 -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
echo "Tag version : $TAG"
echo "Package version: $PKG"
[ "$TAG" = "$PKG" ] || { echo "ERROR: tag v$TAG does not match pyproject.toml version $PKG"; exit 1; }
build_wheels:
name: Build wheels on ${{ matrix.os }} (${{ matrix.arch }})
needs: verify_version
# always() + explicit check, not the default if:success() -- success()
# walks the *entire transitive* needs chain, not just direct needs, so
# it would see release-please's skip (verify_version's own ancestor)
# and auto-skip this job too even though verify_version itself
# succeeded. Confirmed empirically via a workflow_dispatch rehearsal.
if: always() && needs.verify_version.result == 'success'
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: ubuntu-latest
arch: x86_64
- os: ubuntu-24.04-arm
arch: arm64
- os: windows-latest
arch: x86_64
- os: macos-latest
arch: arm64
steps:
- uses: actions/checkout@v7
- name: Build wheels
uses: pypa/cibuildwheel@v4.1.1
- uses: actions/upload-artifact@v7
with:
name: wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: ./wheelhouse/*.whl
build_pyodide:
name: Build pure-Python wheel (for Pyodide/JupyterLite)
needs: verify_version
# See build_wheels' comment above for why always() + an explicit check
# is needed instead of the default if:success().
if: always() && needs.verify_version.result == 'success'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: "3.12"
# Not a cross-compile: RTB_PURE_WHEEL=1 (see pyproject.toml's
# scikit-build-core override) skips both _fknm_c/_frne_c (they have
# complete, tested pure-Python fallbacks -- fknm.py/frne.py,
# tests/test_fknm_fallback.py) and forces the wheel tag to
# py3-none-any. No Emscripten SDK, no cibuildwheel Pyodide platform,
# no Pyodide-version coupling at all -- a plain wheel built on a
# normal runner. This replaced an earlier approach that cross-compiled
# a real wasm32 binary via cibuildwheel's Pyodide platform, which tied
# the wheel to one specific Pyodide/Emscripten ABI version and, worse,
# to a JSPI-safe-vs-unsafe split (Safari/Firefox lack WebAssembly JSPI,
# which Pyodide >=0.27.7 needs) -- see git history on this job and on
# pyproject.toml for that saga. A pure-Python wheel has no ABI to be
# wrong about, so none of that applies here.
- name: Build pure-Python wheel
run: |
pip install build
RTB_PURE_WHEEL=1 python3 -m build --wheel --outdir wheelhouse
- name: Verify wheel is genuinely pure Python
run: |
ls wheelhouse/
case "$(ls wheelhouse/)" in
*-py3-none-any.whl) echo "OK: py3-none-any" ;;
*) echo "ERROR: expected a py3-none-any wheel"; exit 1 ;;
esac
- uses: actions/upload-artifact@v7
with:
name: wheels-pyodide
path: ./wheelhouse/*.whl
build_sdist:
name: Build source distribution
needs: verify_version
# See build_wheels' comment above for why always() + an explicit check
# is needed instead of the default if:success().
if: always() && needs.verify_version.result == 'success'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Build sdist
run: pipx run build --sdist
- uses: actions/upload-artifact@v7
with:
name: sdist
path: dist/*.tar.gz
smoke_test:
name: Smoke-test Linux wheel
needs: build_wheels
# See build_wheels' comment above for why always() + an explicit check
# is needed instead of the default if:success().
if: always() && needs.build_wheels.result == 'success'
runs-on: ubuntu-latest
steps:
- uses: actions/setup-python@v7
with:
python-version: "3.12"
- uses: actions/download-artifact@v8
with:
pattern: wheels-ubuntu-latest-*
merge-multiple: true
path: wheelhouse
- name: Install wheel (pulls all deps from PyPI)
run: pip install --find-links wheelhouse roboticstoolbox-python
- name: Smoke test
run: python -c "import roboticstoolbox; print('OK', roboticstoolbox.__version__)"
upload_pypi:
needs: [build_wheels, build_pyodide, build_sdist, smoke_test]
# See build_wheels' comment above for why always() + an explicit check
# is needed instead of the default if:success().
if: >
always() &&
needs.build_wheels.result == 'success' &&
needs.build_pyodide.result == 'success' &&
needs.build_sdist.result == 'success' &&
needs.smoke_test.result == 'success'
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write # required for OIDC trusted publishing
steps:
- uses: actions/download-artifact@v8
with:
pattern: wheels-*
merge-multiple: true
path: dist
- uses: actions/download-artifact@v8
with:
name: sdist
path: dist
# The pyodide wheel (py3-none-any) uploads to PyPI like any other
# wheel now -- no tag rejection, no GitHub-Release-asset workaround.
# See build_pyodide's comment for why.
- uses: pypa/gh-action-pypi-publish@release/v1
with:
skip-existing: true