docs: add LeRobot and SO-101 getting-started guide #1161
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | |
| # SPDX-License-Identifier: Apache-2.0 | |
| # | |
| # Build docs and Teleop web app, then deploy to GitHub Pages. | |
| # - Push to main/release/v* tag (canonical repo): deploy docs at site root, web app at /client/<slug>/. | |
| # Tag pushes also promote /client/stable/ to the highest v* tag. | |
| # - Same-repo PR: auto-deploy preview to preview/pr-<N>/. | |
| # - Fork PR: build only; a maintainer can deploy via `/preview-docs` (see | |
| # docs-preview-on-demand.yaml). | |
| # | |
| # Builds are gated on changed paths by the `changes` job; gh-pages | |
| # `keep_files: true` preserves whichever artifact was skipped. | |
| # | |
| # Web client uses the private CloudXR SDK for pushes and for PRs whose | |
| # author is in ALLOWED_CLOUDXR_JS_PR_AUTHORS (Repo Settings → Variables); | |
| # all other PRs fall back to the public SDK. | |
| name: Build & deploy docs | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - 'release/**' | |
| tags: | |
| - 'v[1-9]*.[0-9]*.[0-9]*' | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| paths: | |
| - "docs/**" | |
| - ".github/workflows/docs.yaml" | |
| - ".github/actions/build-cloudxr-web-client/**" | |
| - "deps/cloudxr/webxr_client/**" | |
| - "deps/cloudxr/.env.default" | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| check-repo: | |
| name: Check repo | |
| runs-on: ubuntu-latest | |
| permissions: {} | |
| outputs: | |
| is-canonical-repo: ${{ steps.is-canonical-repo.outputs.defined }} | |
| is-deploy-branch: ${{ steps.is-deploy-branch.outputs.defined }} | |
| use_ngc_key: ${{ steps.ngc-allowlist.outputs.use_ngc_key }} | |
| steps: | |
| - id: is-canonical-repo | |
| if: github.repository == 'NVIDIA/IsaacTeleop' | |
| run: echo "defined=true" >> "$GITHUB_OUTPUT" | |
| - id: is-deploy-branch | |
| if: >- | |
| github.ref == 'refs/heads/main' | |
| || startsWith(github.ref, 'refs/heads/release/') | |
| || startsWith(github.ref, 'refs/tags/v') | |
| run: echo "defined=true" >> "$GITHUB_OUTPUT" | |
| - id: ngc-allowlist | |
| run: | | |
| if [ "${{ github.event_name }}" != 'pull_request' ]; then | |
| echo "use_ngc_key=true" >> "$GITHUB_OUTPUT" | |
| elif [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then | |
| echo "use_ngc_key=false" >> "$GITHUB_OUTPUT" | |
| else | |
| ACTOR="${{ github.actor }}" | |
| ALLOWED="${{ vars.ALLOWED_CLOUDXR_JS_PR_AUTHORS }}" | |
| # Normalize: remove spaces so "alice, bob" matches like "alice,bob" | |
| ALLOWED="${ALLOWED// /}" | |
| case ",${ALLOWED}," in | |
| *",${ACTOR},"*) echo "use_ngc_key=true" >> "$GITHUB_OUTPUT" ;; | |
| *) echo "use_ngc_key=false" >> "$GITHUB_OUTPUT" ;; | |
| esac | |
| fi | |
| # gh-pages keep_files preserves whichever artifact isn't rebuilt this run. | |
| changes: | |
| name: Detect changed paths | |
| runs-on: ubuntu-latest | |
| permissions: {} | |
| outputs: | |
| docs: ${{ steps.filter.outputs.docs }} | |
| webapp: ${{ steps.filter.outputs.webapp }} | |
| steps: | |
| - name: Checkout (with history) | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - id: filter | |
| env: | |
| EVENT: ${{ github.event_name }} | |
| BEFORE: ${{ github.event.before }} | |
| BASE_REF: ${{ github.base_ref }} | |
| run: | | |
| set -euo pipefail | |
| if [ "$EVENT" = 'pull_request' ]; then | |
| git fetch --no-tags --depth=1 origin "$BASE_REF" | |
| base="$(git merge-base FETCH_HEAD HEAD || true)" | |
| elif [ -n "$BEFORE" ] && [ "$BEFORE" != '0000000000000000000000000000000000000000' ]; then | |
| base="$BEFORE" | |
| else | |
| base="" # new branch / force push: treat everything as changed | |
| fi | |
| files="$([ -n "$base" ] && git diff --name-only "$base" HEAD || git ls-tree -r --name-only HEAD)" | |
| docs=false; webapp=false | |
| while IFS= read -r f; do | |
| case "$f" in | |
| docs/*|.github/workflows/docs.yaml) docs=true ;; | |
| esac | |
| case "$f" in | |
| deps/cloudxr/webxr_client/*|deps/cloudxr/.env.default|.github/actions/build-cloudxr-web-client/*|.github/workflows/docs.yaml) | |
| webapp=true ;; | |
| esac | |
| done <<< "$files" | |
| echo "docs=$docs" >> "$GITHUB_OUTPUT" | |
| echo "webapp=$webapp" >> "$GITHUB_OUTPUT" | |
| echo "::notice::changes: docs=$docs webapp=$webapp (base=${base:-<none>})" | |
| build-docs: | |
| name: Build Docs | |
| runs-on: ubuntu-latest | |
| needs: [check-repo, changes] | |
| if: needs.changes.outputs.docs == 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.11" | |
| - name: Install docs requirements | |
| working-directory: ./docs | |
| run: pip install -r requirements.txt | |
| - name: Build docs for the current branch | |
| working-directory: ./docs | |
| run: make current-docs | |
| - name: Generate multi-version docs | |
| working-directory: ./docs | |
| if: needs.check-repo.outputs.is-canonical-repo == 'true' && needs.check-repo.outputs.is-deploy-branch == 'true' | |
| run: | | |
| git fetch --prune --unshallow --tags | |
| make multi-docs | |
| - name: Upload docs artifact | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: docs-html | |
| path: ./docs/build | |
| build-app: | |
| name: Build Teleop Web App | |
| runs-on: ubuntu-latest | |
| needs: [check-repo, changes] | |
| if: needs.changes.outputs.webapp == 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| # Allowlist no → public only. Allowlist yes + NGC_API_KEY → private only. | |
| - name: Build CloudXR web client | |
| uses: ./.github/actions/build-cloudxr-web-client | |
| with: | |
| ngc-api-key: ${{ needs.check-repo.outputs.use_ngc_key == 'true' && secrets.NGC_TELEOP_CORE_GITHUB_SERVICE_KEY || '' }} | |
| - name: Upload web app artifact | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: webapp | |
| path: deps/cloudxr/webxr_client/build | |
| deploy-docs: | |
| name: Deploy docs | |
| runs-on: ubuntu-latest | |
| needs: [check-repo, changes, build-docs, build-app] | |
| if: >- | |
| !cancelled() | |
| && needs.check-repo.outputs.is-canonical-repo == 'true' | |
| && (needs.check-repo.outputs.is-deploy-branch == 'true' || github.event_name == 'pull_request') | |
| && needs.build-docs.result != 'failure' | |
| && needs.build-app.result != 'failure' | |
| && (needs.build-docs.result == 'success' || needs.build-app.result == 'success') | |
| permissions: | |
| contents: write # push to gh-pages | |
| steps: | |
| - name: Checkout (for tag lookup) | |
| if: github.event_name == 'push' && github.ref_type == 'tag' | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 1 | |
| - name: Download docs artifact | |
| if: needs.build-docs.result == 'success' | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: docs-html | |
| path: ./docs/build | |
| - name: Download web app artifact | |
| if: needs.build-app.result == 'success' | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: webapp | |
| path: ./webapp | |
| # Web client lands at client/<slug>/: tag → v1.2.3, main → main, release branch → release-1.3.x. | |
| # Tag pushes also (re)point client/stable/ at the highest v* tag. | |
| # The root client/ redirect is owned by the main branch deploy and points at ./stable/. | |
| - name: Place web app under versioned subpath | |
| if: needs.build-app.result == 'success' | |
| run: | | |
| set -euo pipefail | |
| CLIENT_BASE=./docs/build/client | |
| if [ "${{ github.event_name }}" = 'pull_request' ]; then | |
| mkdir -p ./docs/build/current/client | |
| cp -r ./webapp/. ./docs/build/current/client/ | |
| exit 0 | |
| fi | |
| if [ "$GITHUB_REF_TYPE" = 'tag' ]; then | |
| target="$GITHUB_REF_NAME" | |
| else | |
| target="${GITHUB_REF_NAME//\//-}" | |
| fi | |
| mkdir -p "$CLIENT_BASE/$target" | |
| cp -r ./webapp/. "$CLIENT_BASE/$target/" | |
| echo "Deployed web client to /client/$target/" | |
| if [ "$GITHUB_REF" = 'refs/heads/main' ]; then | |
| cat > "$CLIENT_BASE/index.html" <<'HTML' | |
| <!-- SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. --> | |
| <!-- SPDX-License-Identifier: Apache-2.0 --> | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>Redirecting to the stable Isaac Teleop web client</title> | |
| <meta charset="utf-8"> | |
| <meta http-equiv="refresh" content="0; url=./stable/"> | |
| <link rel="canonical" href="./stable/"> | |
| </head> | |
| <body> | |
| <p>Redirecting to <a href="./stable/">the stable Isaac Teleop web client</a>.</p> | |
| <script>location.replace('./stable/' + location.search + location.hash);</script> | |
| </body> | |
| </html> | |
| HTML | |
| fi | |
| if [ "$GITHUB_REF_TYPE" = 'tag' ]; then | |
| stable_slug="$(git ls-remote --tags origin 'v[1-9]*.[0-9]*.[0-9]*' \ | |
| | awk -F'refs/tags/' '{print $2}' \ | |
| | sed 's/\^{}$//' | sort -uV | tail -n1)" | |
| if [ -z "$stable_slug" ]; then | |
| echo "::warning::No v* tags resolved; leaving client/stable/ untouched." | |
| exit 0 | |
| fi | |
| mkdir -p "$CLIENT_BASE/stable" | |
| cat > "$CLIENT_BASE/stable/index.html" <<HTML | |
| <!-- SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. --> | |
| <!-- SPDX-License-Identifier: Apache-2.0 --> | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>Redirecting to the stable Isaac Teleop web client (${stable_slug})</title> | |
| <meta charset="utf-8"> | |
| <meta http-equiv="refresh" content="0; url=../${stable_slug}/"> | |
| <link rel="canonical" href="../${stable_slug}/"> | |
| </head> | |
| <body> | |
| <p>Redirecting to <a href="../${stable_slug}/">the stable Isaac Teleop web client</a>.</p> | |
| <script>location.replace('../${stable_slug}/' + location.search + location.hash);</script> | |
| </body> | |
| </html> | |
| HTML | |
| echo "Stable now points to /client/${stable_slug}/" | |
| fi | |
| - name: Deploy to gh-pages | |
| if: github.event_name == 'push' && needs.check-repo.outputs.is-deploy-branch == 'true' | |
| uses: peaceiris/actions-gh-pages@v4 | |
| with: | |
| github_token: ${{ secrets.GITHUB_TOKEN }} | |
| publish_dir: ./docs/build | |
| keep_files: true | |
| # Fork PRs have a read-only GITHUB_TOKEN and can't push to gh-pages, so | |
| # the auto-deploy is gated to same-repo PRs. Fork PR previews are | |
| # handled by docs-preview-on-demand.yaml (slash-command triggered). | |
| - name: Deploy PR preview to gh-pages | |
| if: >- | |
| github.event_name == 'pull_request' | |
| && github.event.pull_request.head.repo.full_name == github.repository | |
| uses: peaceiris/actions-gh-pages@v4 | |
| with: | |
| github_token: ${{ secrets.GITHUB_TOKEN }} | |
| publish_dir: ./docs/build/current | |
| destination_dir: preview/pr-${{ github.event.pull_request.number }} | |
| keep_files: true | |
| - name: Add preview URL to workflow summary | |
| if: >- | |
| github.event_name == 'pull_request' | |
| && github.event.pull_request.head.repo.full_name == github.repository | |
| run: | | |
| base="https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/preview/pr-${{ github.event.pull_request.number }}/" | |
| client_url="${base}client/" | |
| { | |
| echo "## Docs preview" | |
| echo | |
| echo "Built docs for this PR are available at:" | |
| echo | |
| echo "**${base}**" | |
| echo | |
| echo "Teleop web app (subpath \`/client/\`): **${client_url}**" | |
| echo | |
| echo "(It may take a minute to appear after the workflow completes.)" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| - name: Note manual-trigger requirement for fork PRs | |
| if: >- | |
| github.event_name == 'pull_request' | |
| && github.event.pull_request.head.repo.full_name != github.repository | |
| run: | | |
| { | |
| echo "## Docs preview" | |
| echo | |
| echo "This PR is from a fork, so the preview is **not auto-deployed**." | |
| echo "A maintainer with write access can comment \`/preview-docs\` on" | |
| echo "the PR to deploy a preview to:" | |
| echo | |
| echo "**https://nvidia.github.io/IsaacTeleop/preview/pr-${{ github.event.pull_request.number }}/**" | |
| } >> "$GITHUB_STEP_SUMMARY" |