diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 2e32a13..567cbb6 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -22,13 +22,27 @@ concurrency: cancel-in-progress: false jobs: + gitlink-freshness: + # Gate: every tracked gitlink must be at the tip of its sibling repo's + # default branch, so the workspace pointers can't silently drift behind + # merged work. Uses ls-remote (no sibling checkout needed). + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Check gitlinks are at their default-branch tips + env: + GH_TOKEN: ${{ secrets.SIBLING_CHECKOUT_TOKEN || secrets.GITHUB_TOKEN }} + run: | + git config --global url."https://x-access-token:${GH_TOKEN}@github.com/personalrobotics/".insteadOf "https://github.com/personalrobotics/" + ./scripts/check_gitlink_freshness.sh + integration: runs-on: ubuntu-latest timeout-minutes: 45 strategy: fail-fast: false matrix: - python-version: ["3.10", "3.12"] + python-version: ["3.11", "3.12"] steps: - name: Checkout robot-code uses: actions/checkout@v4 @@ -74,7 +88,7 @@ jobs: run: | set +e fail=0 - for d in asset_manager geodude geodude_assets mj_environment mj_manipulator mj_viser prl_assets pycbirrt tsr; do + for d in ada_assets ada_mj asset_manager geodude geodude_assets mj_environment mj_manipulator mj_viser prl_assets pycbirrt tsr; do if [ -d "$d/tests" ]; then echo "::group::$d tests" (cd "$d" && uv run pytest tests/ -q) || fail=1 @@ -88,10 +102,10 @@ jobs: - name: Import smoke check run: | - uv run python -c "import asset_manager, geodude, geodude_assets, mj_environment, mj_manipulator, mj_viser, prl_assets, pycbirrt, tsr; print('all imports OK')" + uv run python -c "import ada_assets, ada_mj, asset_manager, geodude, geodude_assets, mj_environment, mj_manipulator, mj_viser, prl_assets, pycbirrt, tsr; print('all imports OK')" notify-on-nightly-failure: - needs: integration + needs: [integration, gitlink-freshness] if: failure() && github.event_name == 'schedule' runs-on: ubuntu-latest permissions: diff --git a/scripts/check_gitlink_freshness.sh b/scripts/check_gitlink_freshness.sh new file mode 100755 index 0000000..c4632ad --- /dev/null +++ b/scripts/check_gitlink_freshness.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# Fail if any tracked gitlink (submodule-style commit pointer) is not at the +# tip of its sibling repo's DEFAULT branch. This is what keeps the workspace +# pointers from silently drifting behind merged work. +# +# It compares the committed gitlink SHA against `git ls-remote HEAD`, the +# remote's default-branch tip -- so it is correct for repos whose default is not +# `main` (e.g. ada_feeding -> ros2-devel) without any per-repo configuration. +# +# No sibling checkout is required (uses ls-remote), so it is cheap to run in CI. +# Sibling URLs are derived by convention: github.com/personalrobotics/. +# +# Usage: scripts/check_gitlink_freshness.sh +# Exit: 0 = all current; 1 = drift or lookup failure (fail closed). +set -euo pipefail + +cd "$(git rev-parse --show-toplevel)" + +ORG_URL="https://github.com/personalrobotics" +stale=0 +errors=0 + +printf "%-22s %-12s %-12s %s\n" "GITLINK" "RECORDED" "REMOTE-TIP" "STATUS" +printf -- "%.0s-" {1..64}; printf "\n" + +# Each gitlink: mode 160000, " ". +while read -r sha path; do + url="$ORG_URL/$(basename "$path")" + tip="$(git ls-remote "$url" HEAD 2>/dev/null | awk 'NR==1{print $1}')" + if [ -z "$tip" ]; then + printf "%-22s %-12s %-12s %s\n" "$path" "${sha:0:11}" "??" "LOOKUP-FAILED" + errors=1 + continue + fi + if [ "$sha" = "$tip" ]; then + printf "%-22s %-12s %-12s %s\n" "$path" "${sha:0:11}" "${tip:0:11}" "ok" + else + printf "%-22s %-12s %-12s %s\n" "$path" "${sha:0:11}" "${tip:0:11}" "STALE" + stale=1 + fi +done < <(git ls-tree -r HEAD | awk '$2=="commit"{print $3, $4}') + +echo +if [ "$errors" -ne 0 ]; then + echo "ERROR: could not resolve one or more sibling default branches (see LOOKUP-FAILED)." + exit 1 +fi +if [ "$stale" -ne 0 ]; then + echo "Gitlinks are behind their default-branch tips. To fix, for each STALE repo:" + echo " (cd && git fetch origin && git checkout \"\$(git rev-parse origin/HEAD)\")" + echo " git add && git commit" + exit 1 +fi +echo "All gitlinks are at their default-branch tips." diff --git a/setup.sh b/setup.sh index 1f25f79..0fecc72 100755 --- a/setup.sh +++ b/setup.sh @@ -4,7 +4,18 @@ # the shared Python environment. set -euo pipefail +# Every sibling repo the workspace tracks. The ADA repos (ada_assets, ada_mj) +# are uv workspace members, so omitting them breaks `uv sync` on a fresh clone; +# the ROS 2 repos (ada_ros2, ada_feeding, articutool_ros2) are not Python +# packages but are part of the workspace. This list must stay in sync with the +# tracked gitlinks — scripts/check_gitlink_freshness.sh gates that they are not +# stale. ada_feeding's default branch is ros2-devel (git clone picks it up). REPOS=( + "https://github.com/personalrobotics/ada_assets" + "https://github.com/personalrobotics/ada_feeding" + "https://github.com/personalrobotics/ada_mj" + "https://github.com/personalrobotics/ada_ros2" + "https://github.com/personalrobotics/articutool_ros2" "https://github.com/personalrobotics/asset_manager" "https://github.com/personalrobotics/geodude" "https://github.com/personalrobotics/geodude_assets"