From d4f962fb34ae3bb2265fb241b50c9e3f6e85a798 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Fri, 25 Jul 2025 12:06:46 +0200 Subject: [PATCH] feat(ci): add entrypoints + add version checks + add minimal release testing + uncomment publishing to pypi (#1589) --- .github/workflows/full_tests.yml | 2 + .github/workflows/release.yml | 77 +++++++++++++++++++++++++------- pyproject.toml | 11 +++++ 3 files changed, 74 insertions(+), 16 deletions(-) diff --git a/.github/workflows/full_tests.yml b/.github/workflows/full_tests.yml index 55d38883..d16fe5e7 100644 --- a/.github/workflows/full_tests.yml +++ b/.github/workflows/full_tests.yml @@ -206,3 +206,5 @@ jobs: echo "::error::Failed to delete Docker image. HTTP status: $HTTP_RESPONSE" exit 1 fi + +# TODO(Steven): Check dockerimages pull in ubuntu diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7d80ac5a..32c1c605 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,12 +20,12 @@ on: - 'v*.*.*' # Trigger on tags like v0.1.0, v1.0.0 jobs: - # TODO(Steven): Publish draft/pre-release and to test pypi - # TODO(Steven): Tag documentation with the same version as the package - # TODO(Steven): Define entry points for main CLI scripts + # This job builds the Python package and publishes it to PyPI build-and-publish: name: Build and publish Python distributions runs-on: ubuntu-latest + outputs: + version: ${{ steps.extract_info.outputs.tag_version }} permissions: contents: write id-token: write @@ -41,26 +41,34 @@ jobs: with: python-version: '3.10' - - name: Extract Version and Package Name + - name: Extract Version id: extract_info + # Extract version from tag (e.g., v0.1.0 -> 0.1.0) # zizmor: ignore[template-injection] run: | - # Extract version from tag (e.g., v0.1.0 -> 0.1.0) VERSION=${{ github.ref_name }} VERSION_NUMBER=${VERSION#v} echo "tag_version=$VERSION_NUMBER" >> $GITHUB_OUTPUT + - name: Check if version matches pyproject.toml + # zizmor: ignore[template-injection] + run: | + TAG_VERSION=${{ steps.extract_info.outputs.tag_version }} - # Extract package name from pyproject.toml - PACKAGE_NAME=$(grep -oP 'name = "\K[^"]+' pyproject.toml) - echo "package_name=$PACKAGE_NAME" >> $GITHUB_OUTPUT + PYPROJECT_VERSION=$(grep '^version = ' pyproject.toml | awk -F' = ' '{print $2}' | tr -d '"') + + if [[ "$TAG_VERSION" != "$PYPROJECT_VERSION" ]]; then + echo "Error: Tag version ($TAG_VERSION) does not match pyproject.toml version ($PYPROJECT_VERSION)." >&2 + exit 1 + else + echo "Tag version matches pyproject.toml version: $TAG_VERSION. Proceeding with release." + fi - name: Check if version exists on PyPI # zizmor: ignore[template-injection] run: | - PACKAGE_NAME=${{ steps.extract_info.outputs.package_name }} NEW_VERSION=${{ steps.extract_info.outputs.tag_version }} - response=$(curl -s "https://pypi.org/pypi/$PACKAGE_NAME/$NEW_VERSION/json") + response=$(curl -s "https://pypi.org/pypi/lerobot/$NEW_VERSION/json") if echo "$response" | grep -q "message"; then echo "Version $NEW_VERSION is available on PyPI. Proceeding with release." else @@ -80,9 +88,46 @@ jobs: # zizmor: ignore[template-injection] run: gh release create ${{ github.ref_name }} --release-name "Release ${{ github.ref_name }}" --generate-notes ./dist/* - # TODO(Steven): Uncomment when ready to publish to PyPI - # - name: Publish to PyPI - # if: startsWith(github.ref, 'refs/tags/v') - # uses: pypa/gh-action-pypi-publish@v1.12.4 - # with: - # password: ${{ secrets.PYPI_API_TOKEN }} + - name: Publish to PyPI + if: startsWith(github.ref, 'refs/tags/v') + uses: pypa/gh-action-pypi-publish@v1.12.4 # zizmor: ignore[unpinned-uses, use-trusted-publishing] + with: + password: ${{ secrets.PYPI_API_TOKEN }} + + # This job runs end-to-end tests on the release + test-release: + name: Test Release + needs: [build-and-publish] + runs-on: ubuntu-latest + permissions: + contents: read + env: + MUJOCO_GL: egl + steps: + - uses: actions/checkout@v4 + with: + lfs: true + persist-credentials: false + - name: Install apt dependencies + run: | + sudo apt-get update && sudo apt-get install -y build-essential \ + git curl libglib2.0-0 libegl1-mesa-dev ffmpeg libusb-1.0-0-dev \ + speech-dispatcher libgeos-dev portaudio19-dev + - name: Setup uv and Python + uses: astral-sh/setup-uv@v6 # zizmor: ignore[unpinned-uses] + with: + enable-cache: true + version: ${{ env.UV_VERSION }} + python-version: ${{ env.PYTHON_VERSION }} + - name: Install lerobot release + run: uv run pip install lerobot==${{ needs.build-and-publish.outputs.version }} # zizmor: ignore[template-injection] + + - name: Check lerobot version + run: uv run lerobot --version + + - name: Run end-to-end tests + run: uv run make test-end-to-end + + +# TODO(Steven): Publish draft/pre-release and to test pypi +# TODO(Steven): Tag documentation with the same version as the package diff --git a/pyproject.toml b/pyproject.toml index 7a0ad148..a05d5c24 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -156,6 +156,17 @@ all = [ "lerobot[xarm]" ] +[project.scripts] +lerobot-calibrate="lerobot.calibrate:main" +lerobot-find-cameras="lerobot.find_cameras:main" +lerobot-find-port="lerobot.find_port:main" +lerobot-record="lerobot.record:main" +lerobot-replay="lerobot.replay:main" +lerobot-setup-motors="lerobot.setup_motors:main" +lerobot-teleoperate="lerobot.teleoperate:main" +lerobot-eval="lerobot.scripts.eval:main" +lerobot-train="lerobot.scripts.train:main" + # ---------------- Tool Configurations ---------------- [tool.setuptools.packages.find] where = ["src"]