diff --git a/.github/workflows/automerge.yaml b/.github/workflows/automerge.yaml index d81fb9c0..14d76eca 100644 --- a/.github/workflows/automerge.yaml +++ b/.github/workflows/automerge.yaml @@ -25,6 +25,17 @@ jobs: cancel-in-progress: false runs-on: ubuntu-latest steps: + # the base branch (pull_request_target's default), for pixi's gh: never the pull request's code + - uses: actions/checkout@v6 + with: + persist-credentials: false + - name: Disable git auto-maintenance + run: git config --global maintenance.auto false && git config --global gc.auto 0 + - uses: prefix-dev/setup-pixi@v0.11.0 + with: + locked: true # the lock file must match pixi.toml + pixi-version: v0.81.0 + cache-write: false # the build jobs save the pixi environment cache # The merge has to come from the bot (or a PAT): a merge made with the # workflow's own token would not trigger the main build workflow. - name: Bot token @@ -42,15 +53,15 @@ jobs: run: | # labeled/unlabeled events can arrive out of order: go by the label the # pull request has now, not by the event - enabled=$(gh pr view "$PR" --json labels --jq 'any(.labels[]; .name == "automerge")') + enabled=$(pixi run gh pr view "$PR" --json labels --jq 'any(.labels[]; .name == "automerge")') if [ "$enabled" = true ]; then if [ -z "$BOT_TOKEN" ]; then echo "::error::auto-merge needs the bot app (ROBOSTACK_BOT_CLIENT_ID + ROBOSTACK_BOT_PRIVATE_KEY) or GHA_PAT: a merge with the workflow token doesn't start the build workflow" exit 1 fi - GH_TOKEN="$BOT_TOKEN" gh pr merge "$PR" --auto --merge + GH_TOKEN="$BOT_TOKEN" pixi run gh pr merge "$PR" --auto --merge else - gh pr merge "$PR" --disable-auto + pixi run gh pr merge "$PR" --disable-auto fi drop-on-push: @@ -62,6 +73,17 @@ jobs: cancel-in-progress: false runs-on: ubuntu-latest steps: + # the base branch (pull_request_target's default), for pixi's gh: never the pull request's code + - uses: actions/checkout@v6 + with: + persist-credentials: false + - name: Disable git auto-maintenance + run: git config --global maintenance.auto false && git config --global gc.auto 0 + - uses: prefix-dev/setup-pixi@v0.11.0 + with: + locked: true # the lock file must match pixi.toml + pixi-version: v0.81.0 + cache-write: false # the build jobs save the pixi environment cache # removing the label with this token doesn't start the unlabeled run above, so # turn auto-merge off here as well - name: Remove the automerge label @@ -71,6 +93,6 @@ jobs: BEFORE: ${{ github.event.before }} AFTER: ${{ github.event.after }} run: | - gh pr edit "$PR" --remove-label automerge - gh pr merge "$PR" --disable-auto || true - gh pr comment "$PR" --body "New commits (${BEFORE:0:7}..${AFTER:0:7}) arrived after the \`automerge\` label was added, so the label was removed and auto-merge turned off. Add the label again once the new commits are reviewed." + pixi run gh pr edit "$PR" --remove-label automerge + pixi run gh pr merge "$PR" --disable-auto || true + pixi run gh pr comment "$PR" --body "New commits (${BEFORE:0:7}..${AFTER:0:7}) arrived after the \`automerge\` label was added, so the label was removed and auto-merge turned off. Add the label again once the new commits are reviewed." diff --git a/.github/workflows/bot.yaml b/.github/workflows/bot.yaml index 7da3c7da..12e0423d 100644 --- a/.github/workflows/bot.yaml +++ b/.github/workflows/bot.yaml @@ -198,7 +198,7 @@ jobs: echo echo "[Workflow run]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID)" } > "$RUNNER_TEMP/comment.md" - gh issue comment "$NUMBER" --repo "$GITHUB_REPOSITORY" --body-file "$RUNNER_TEMP/comment.md" + pixi run gh issue comment "$NUMBER" --repo "$GITHUB_REPOSITORY" --body-file "$RUNNER_TEMP/comment.md" if [ "$GITHUB_EVENT_NAME" = issues ] && [ "${{ job.status }}" = success ] && [ "${{ matrix.command }}" != add-package ]; then - gh issue close "$NUMBER" --repo "$GITHUB_REPOSITORY" + pixi run gh issue close "$NUMBER" --repo "$GITHUB_REPOSITORY" fi diff --git a/.github/workflows/testpr.yaml b/.github/workflows/testpr.yaml index e32b07b4..36644a32 100644 --- a/.github/workflows/testpr.yaml +++ b/.github/workflows/testpr.yaml @@ -35,6 +35,13 @@ jobs: with: persist-credentials: false fetch-depth: 0 + - name: Disable git auto-maintenance + run: git config --global maintenance.auto false && git config --global gc.auto 0 + - uses: prefix-dev/setup-pixi@v0.11.0 + with: + locked: true # the lock file must match pixi.toml + pixi-version: v0.81.0 + cache-write: false # the build jobs save the pixi environment cache - name: Which distributions changed id: plan env: @@ -43,16 +50,15 @@ jobs: SELECTED: ${{ inputs.distros }} GH_TOKEN: ${{ github.token }} run: | - # plain python + PyYAML of the runner image; no pixi needed for this if [ -n "$SELECTED" ]; then - distros=$(python3 -c 'import json,os; print(json.dumps(os.environ["SELECTED"].split()))') + distros=$(pixi run python -c 'import json,os; print(json.dumps(os.environ["SELECTED"].split()))') elif [ -n "$BASE" ]; then # build: labels limit the build to those distributions; read now (not # from the event) so that a re-run sees labels added after the push - labels=$(gh pr view "$PR" --repo "$GITHUB_REPOSITORY" --json labels -q '[.labels[].name]') - distros=$(python3 tools/robostack.py changed-distros --base "$BASE" --labels "$labels") + labels=$(pixi run gh pr view "$PR" --repo "$GITHUB_REPOSITORY" --json labels -q '[.labels[].name]') + distros=$(pixi run python tools/robostack.py changed-distros --base "$BASE" --labels "$labels") else - distros=$(python3 tools/robostack.py changed-distros --base HEAD --all) + distros=$(pixi run python tools/robostack.py changed-distros --base HEAD --all) fi echo "distros=$distros" | tee -a "$GITHUB_OUTPUT" @@ -302,16 +308,17 @@ jobs: - name: Drop this pull request's superseded build caches if: ${{ always() && steps.save-cache.outcome == 'success' && github.event.pull_request.number }} continue-on-error: true - shell: bash + shell: bash -l {0} env: GH_TOKEN: ${{ github.token }} PREFIX: ${{ runner.os }}-${{ matrix.distro }}-${{ matrix.target.platform }}-pr-${{ github.event.pull_request.number }}- KEEP: ${{ runner.os }}-${{ matrix.distro }}-${{ matrix.target.platform }}-pr-${{ github.event.pull_request.number }}-${{ github.run_id }}-${{ github.run_attempt }} run: | - gh cache list --repo "$GITHUB_REPOSITORY" --key "$PREFIX" --limit 100 --json id,key \ + # pixi's gh: the runner's is not on PATH on Windows (Clean up PATH) + pixi run gh cache list --repo "$GITHUB_REPOSITORY" --key "$PREFIX" --limit 100 --json id,key \ --jq ".[] | select(.key != \"$KEEP\") | .id" | while read -r id; do - gh cache delete "$id" --repo "$GITHUB_REPOSITORY" && echo "deleted cache $id" + pixi run gh cache delete "$id" --repo "$GITHUB_REPOSITORY" && echo "deleted cache $id" done - name: Generate the staged build workflows (catches post-merge problems) @@ -336,6 +343,16 @@ jobs: actions: read pull-requests: write steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + - name: Disable git auto-maintenance + run: git config --global maintenance.auto false && git config --global gc.auto 0 + - uses: prefix-dev/setup-pixi@v0.11.0 + with: + locked: true # the lock file must match pixi.toml + pixi-version: v0.81.0 + cache-write: false # the build jobs save the pixi environment cache - uses: actions/download-artifact@v7 with: pattern: abi-check-* @@ -349,7 +366,7 @@ jobs: shopt -s nullglob files=(abi-check-*.md) marker='' - existing=$(gh api "repos/$REPO/issues/$PR/comments" --paginate -q ".[] | select(.body | startswith(\"$marker\")) | .id" | head -1) + existing=$(pixi run gh api "repos/$REPO/issues/$PR/comments" --paginate -q ".[] | select(.body | startswith(\"$marker\")) | .id" | head -1) # no comment for pull requests that build nothing released before if ! grep -q '^| package |' "${files[@]}" /dev/null && [ -z "$existing" ]; then exit 0; fi { @@ -368,9 +385,9 @@ jobs: echo "" } > body.md if [ -n "$existing" ]; then - gh api -X PATCH "repos/$REPO/issues/comments/$existing" -F body=@body.md > /dev/null + pixi run gh api -X PATCH "repos/$REPO/issues/comments/$existing" -F body=@body.md > /dev/null else - gh api "repos/$REPO/issues/$PR/comments" -F body=@body.md > /dev/null + pixi run gh api "repos/$REPO/issues/$PR/comments" -F body=@body.md > /dev/null fi # One stable check for branch protection / auto-merge: the build matrix differs diff --git a/pixi.lock b/pixi.lock index e246a48a..51ff7b8a 100644 --- a/pixi.lock +++ b/pixi.lock @@ -40,6 +40,7 @@ environments: - conda: https://prefix.dev/conda-forge/linux-64/bzip2-1.0.8-hda65f42_10.conda - conda: https://prefix.dev/conda-forge/linux-64/c-ares-1.34.8-hebe6cf0_2.conda - conda: https://prefix.dev/conda-forge/linux-64/cmake-3.31.8-hc85cc9f_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/gh-2.102.0-hfc2019e_0.conda - conda: https://prefix.dev/conda-forge/linux-64/git-lfs-3.8.0-h2c09266_0.conda - conda: https://prefix.dev/conda-forge/linux-64/icu-78.3-py310h44b86e0_2.conda - conda: https://prefix.dev/conda-forge/linux-64/keyutils-1.6.3-h7cc23a3_1.conda @@ -89,7 +90,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/tomli-2.5.0-pyh5ded981_0.conda - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - - pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=63469bad308fe64612410eb2d9f7098e3fb34912#63469bad308fe64612410eb2d9f7098e3fb34912 + - pypi: git+https://github.com/RoboStack/vinca.git?rev=3d552f4001634fd26376b2bf5fe37fe81ef3dc22#3d552f4001634fd26376b2bf5fe37fe81ef3dc22 - pypi: https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/74/ef303ec980ef962ffe548fa36cb138bb399d1d1315731ba7bb81da85f7e0/rosdistro-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl @@ -119,6 +120,7 @@ environments: - conda: https://prefix.dev/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_10.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/c-ares-1.34.8-h29ee22c_2.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/cmake-3.31.8-hc9d863e_0.conda + - conda: https://prefix.dev/conda-forge/linux-aarch64/gh-2.102.0-h22914b5_0.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/git-lfs-3.8.0-hcf061c0_0.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/icu-78.3-py311h3512406_2.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/keyutils-1.6.3-h5bc82ec_1.conda @@ -168,7 +170,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/tomli-2.5.0-pyh5ded981_0.conda - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - - pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=63469bad308fe64612410eb2d9f7098e3fb34912#63469bad308fe64612410eb2d9f7098e3fb34912 + - pypi: git+https://github.com/RoboStack/vinca.git?rev=3d552f4001634fd26376b2bf5fe37fe81ef3dc22#3d552f4001634fd26376b2bf5fe37fe81ef3dc22 - pypi: https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/74/ef303ec980ef962ffe548fa36cb138bb399d1d1315731ba7bb81da85f7e0/rosdistro-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl @@ -210,6 +212,7 @@ environments: - conda: https://prefix.dev/conda-forge/osx-64/bzip2-1.0.8-h374f1ed_10.conda - conda: https://prefix.dev/conda-forge/osx-64/c-ares-1.34.8-had63097_2.conda - conda: https://prefix.dev/conda-forge/osx-64/cmake-3.31.8-h29fc008_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/gh-2.102.0-h5839d16_0.conda - conda: https://prefix.dev/conda-forge/osx-64/git-lfs-3.8.0-hb8084c2_0.conda - conda: https://prefix.dev/conda-forge/osx-64/icu-78.3-py313hbf1d544_2.conda - conda: https://prefix.dev/conda-forge/osx-64/krb5-1.22.2-h69064fd_2.conda @@ -240,7 +243,7 @@ environments: - conda: https://prefix.dev/conda-forge/osx-64/tk-8.6.13-ha6c374e_4.conda - conda: https://prefix.dev/conda-forge/osx-64/yaml-0.2.5-had63097_3.conda - conda: https://prefix.dev/conda-forge/osx-64/zstd-1.5.7-hbc1a06c_7.conda - - pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=63469bad308fe64612410eb2d9f7098e3fb34912#63469bad308fe64612410eb2d9f7098e3fb34912 + - pypi: git+https://github.com/RoboStack/vinca.git?rev=3d552f4001634fd26376b2bf5fe37fe81ef3dc22#3d552f4001634fd26376b2bf5fe37fe81ef3dc22 - pypi: https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/74/ef303ec980ef962ffe548fa36cb138bb399d1d1315731ba7bb81da85f7e0/rosdistro-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl @@ -282,6 +285,7 @@ environments: - conda: https://prefix.dev/conda-forge/osx-arm64/bzip2-1.0.8-h4e30115_10.conda - conda: https://prefix.dev/conda-forge/osx-arm64/c-ares-1.34.8-h74c22ad_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/cmake-3.31.8-h54ad630_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/gh-2.102.0-hf76c51c_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/git-lfs-3.8.0-h7021a9e_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/icu-78.3-py310h579977c_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/krb5-1.22.2-h34f8a20_2.conda @@ -312,7 +316,7 @@ environments: - conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-hbeba79b_4.conda - conda: https://prefix.dev/conda-forge/osx-arm64/yaml-0.2.5-h74c22ad_3.conda - conda: https://prefix.dev/conda-forge/osx-arm64/zstd-1.5.7-hf451053_7.conda - - pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=63469bad308fe64612410eb2d9f7098e3fb34912#63469bad308fe64612410eb2d9f7098e3fb34912 + - pypi: git+https://github.com/RoboStack/vinca.git?rev=3d552f4001634fd26376b2bf5fe37fe81ef3dc22#3d552f4001634fd26376b2bf5fe37fe81ef3dc22 - pypi: https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/74/ef303ec980ef962ffe548fa36cb138bb399d1d1315731ba7bb81da85f7e0/rosdistro-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl @@ -355,6 +359,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://prefix.dev/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_10.conda - conda: https://prefix.dev/conda-forge/win-64/cmake-3.31.8-hdcbee5b_0.conda + - conda: https://prefix.dev/conda-forge/win-64/gh-2.102.0-h11686cb_0.conda - conda: https://prefix.dev/conda-forge/win-64/git-2.56.0-h57928b3_0.conda - conda: https://prefix.dev/conda-forge/win-64/git-lfs-3.8.0-ha70c05e_0.conda - conda: https://prefix.dev/conda-forge/win-64/icu-78.3-h5112557_2.conda @@ -384,7 +389,7 @@ environments: - conda: https://prefix.dev/conda-forge/win-64/vcomp14-14.51.36247-habf1de7_41.conda - conda: https://prefix.dev/conda-forge/win-64/yaml-0.2.5-h6a83c73_3.conda - conda: https://prefix.dev/conda-forge/win-64/zstd-1.5.7-h534d264_7.conda - - pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=63469bad308fe64612410eb2d9f7098e3fb34912#63469bad308fe64612410eb2d9f7098e3fb34912 + - pypi: git+https://github.com/RoboStack/vinca.git?rev=3d552f4001634fd26376b2bf5fe37fe81ef3dc22#3d552f4001634fd26376b2bf5fe37fe81ef3dc22 - pypi: https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/74/ef303ec980ef962ffe548fa36cb138bb399d1d1315731ba7bb81da85f7e0/rosdistro-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl @@ -477,6 +482,15 @@ packages: run_exports: {} size: 20991288 timestamp: 1757877168657 +- conda: https://prefix.dev/conda-forge/linux-64/gh-2.102.0-hfc2019e_0.conda + sha256: 7c7d9b68063b4a3588190fd82efba2c81a13d361250f4e09e57888ae2ea2cb6f + md5: d933d1442248e72f2559c7dc6df70e30 + license: Apache-2.0 + license_family: APACHE + purls: [] + run_exports: {} + size: 13993962 + timestamp: 1790750717805 - conda: https://prefix.dev/conda-forge/linux-64/git-lfs-3.8.0-h2c09266_0.conda sha256: b69ca1136b045256717d34f464ff9ce2b2df48a7d1953cfec8a0d0b9714c57ce md5: 935cbcbc760832a8b79a3e689f89b3ca @@ -1091,6 +1105,15 @@ packages: run_exports: {} size: 20216587 timestamp: 1757877248575 +- conda: https://prefix.dev/conda-forge/linux-aarch64/gh-2.102.0-h22914b5_0.conda + sha256: df3d569bf607a455acd22f84c10685b308f8d232e941ce732f83ddbeac2d1159 + md5: a81254c263bec3c65036831215c361c3 + license: Apache-2.0 + license_family: APACHE + purls: [] + run_exports: {} + size: 12668666 + timestamp: 1790750712871 - conda: https://prefix.dev/conda-forge/linux-aarch64/git-lfs-3.8.0-hcf061c0_0.conda sha256: 820cd1ef5792bac4550d49a0319c8597f234294452a4589c0fac8cd509e02e06 md5: 410eac0a18d0b689c40884b9b554ace4 @@ -1851,6 +1874,17 @@ packages: run_exports: {} size: 17816621 timestamp: 1757878263595 +- conda: https://prefix.dev/conda-forge/osx-64/gh-2.102.0-h5839d16_0.conda + sha256: b176af4f4a5206d7ee54411a64fc0c920f212f5047e4fb46d88ffe7c2b387a5d + md5: 7c9d65d29932dae4dc5f36f4c30e643d + constrains: + - __osx >=10.12 + license: Apache-2.0 + license_family: APACHE + purls: [] + run_exports: {} + size: 13892584 + timestamp: 1790750786714 - conda: https://prefix.dev/conda-forge/osx-64/git-lfs-3.8.0-hb8084c2_0.conda sha256: 37079e2772cb1b70cbafa4c9ad1f6629996c17db35e402851236e3d1cf479daa md5: cca2a4a0d8503b25a2f4ef9e857af25d @@ -2331,6 +2365,15 @@ packages: run_exports: {} size: 16632236 timestamp: 1757877846468 +- conda: https://prefix.dev/conda-forge/osx-arm64/gh-2.102.0-hf76c51c_0.conda + sha256: 77908dbe0e0f02feacacb1c34ec4cc65a9414bb7c0809ab83ddec26603b6d214 + md5: 37fbfe69ee3d410a7a53433ef640dec5 + license: Apache-2.0 + license_family: APACHE + purls: [] + run_exports: {} + size: 12575213 + timestamp: 1790750717485 - conda: https://prefix.dev/conda-forge/osx-arm64/git-lfs-3.8.0-h7021a9e_0.conda sha256: ded5736ccccf1cef73644da2046f5103973dc6f09dbf2d068ac9bf811554e799 md5: 76d68fb4ba2dcd93f60ab108dbf5b48b @@ -2796,6 +2839,15 @@ packages: run_exports: {} size: 14669008 timestamp: 1757878123930 +- conda: https://prefix.dev/conda-forge/win-64/gh-2.102.0-h11686cb_0.conda + sha256: 618fe7c5162b61595155c47c916e4fbc85138d250f1ecf11afc296afd4463ab8 + md5: d3006da1410c8fa707d0e3b30578038c + license: Apache-2.0 + license_family: APACHE + purls: [] + run_exports: {} + size: 13454091 + timestamp: 1790750711898 - conda: https://prefix.dev/conda-forge/win-64/git-2.56.0-h57928b3_0.conda sha256: 908bc78bf15591b9d093cb4e4c465f75f691f36bf5caa28971394dfa89d0fea0 md5: 67cba859d0f04715565ea5c32c6ab5f7 @@ -3237,7 +3289,7 @@ packages: - zstd >=1.5.7,<1.6.0a0 size: 387535 timestamp: 1786599623274 -- pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=63469bad308fe64612410eb2d9f7098e3fb34912#63469bad308fe64612410eb2d9f7098e3fb34912 +- pypi: git+https://github.com/RoboStack/vinca.git?rev=3d552f4001634fd26376b2bf5fe37fe81ef3dc22#3d552f4001634fd26376b2bf5fe37fe81ef3dc22 name: vinca version: 0.2.0 requires_dist: diff --git a/pixi.toml b/pixi.toml index f17e07dd..716bb690 100644 --- a/pixi.toml +++ b/pixi.toml @@ -1,5 +1,5 @@ [workspace] -name = "robostack-distros" +name = "robostack" description = "RoboStack: conda packages for all ROS 2 distributions, from one repository" authors = ["Tobias Fischer ", "Wolf Vollprecht ", "Silvio Traversaro ", "Daisuke Nishimatsu "] channels = ["https://prefix.dev/conda-forge"] @@ -25,6 +25,8 @@ pyyaml = "*" # Some git repos need git-lfs, see https://github.com/RoboStack/ros-jazzy/issues/118 git-lfs = "*" pytest = ">=9.1.1,<10" +# gh for the workflows: one version everywhere (the runner's is not on PATH on Windows) +gh = ">=2.102.0,<3" [target.win-64.dependencies] # patch is required by rattler-build @@ -34,8 +36,7 @@ git = "*" [pypi-dependencies] # One vinca for all distributions. -# Tobias-Fischer/vinca robostack-integration (extends, test selectors, gha fix, rebuild planner, mutex build number: RoboStack/vinca#163-#169) until merged upstream -vinca = { git = "https://github.com/Tobias-Fischer/vinca.git", rev = "63469bad308fe64612410eb2d9f7098e3fb34912" } +vinca = { git = "https://github.com/RoboStack/vinca.git", rev = "3d552f4001634fd26376b2bf5fe37fe81ef3dc22" } # For local development, temporarily use (and regenerate pixi.lock): # vinca = { path = "../vinca", editable = true } diff --git a/tools/abi_check.py b/tools/abi_check.py index 3fcf15c3..a601256b 100644 --- a/tools/abi_check.py +++ b/tools/abi_check.py @@ -523,7 +523,8 @@ def worst_first(item): counts = [f"**{len(breaking)} need their dependents rebuilt**" if breaking else "", f"{len(attention) - len(breaking)} to review (changed headers)" if len(attention) > len(breaking) else "", f"{len(rest)} can be bumped on their own" if rest else ""] - lines = [f"{distro} {platform}: " + # always collapsed, the summary line shows the counts (breaking ones in bold) + lines = [f"
{distro} {platform}: " f"{', '.join(c for c in counts if c)}", ""] if attention: lines += TABLE_HEADER + [_row(n, r) for n, r in attention] + [""] diff --git a/tools/robostack.py b/tools/robostack.py index be6f3847..fa2de6e5 100644 --- a/tools/robostack.py +++ b/tools/robostack.py @@ -62,6 +62,22 @@ def run(cmd: list[str], cwd: Path) -> int: return subprocess.run(cmd, cwd=cwd).returncode +def run_tee(cmd: list[str], cwd: Path) -> tuple[int, bytes]: + """run(), also returning the combined output.""" + print("+", " ".join(cmd), f" (in {cwd.relative_to(ROOT)})", flush=True) + output = bytearray() + with subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as proc: + for line in proc.stdout: + sys.stdout.buffer.write(line) + sys.stdout.buffer.flush() + output += line + return proc.returncode, bytes(output) + + +WORKFLOW_SIZE_MESSAGE = b"exceeding the 500 KiB limit" +MAX_BATCH_SIZE = 100 + + # prefix.dev's sharded repodata (what rattler reads) lists a new upload a few minutes # after repodata.json does, so a stage that starts right after the previous one # uploaded can find no candidates for a package that is on the channel. @@ -73,7 +89,9 @@ def run(cmd: list[str], cwd: Path) -> int: # continues where it stopped. NETWORK_MESSAGES = (b"Git fetch failed", b"Failed to connect to github.com", b"error sending request for url", b"stream closed because of a broken pipe", b"RPC failed; curl", b"Could not resolve host", - b"connection error") + b"connection error", + # prefix.dev's sharded repodata answers 409 / 5xx now and then while a channel updates + b"HTTP status client error (409 Conflict)", b"HTTP status server error") NETWORK_RETRIES = 4 NETWORK_WAIT = 60 # doubled on each retry: 1, 2, 4, 8 minutes @@ -342,8 +360,16 @@ def generate_gha(distro: str, args: list[str]) -> int: d = work_dir(distro) branch = f"buildbranch_{distro}_{ns.platform.replace('-', '_')}" before = set(d.glob("*.yml")) - rc = run(["vinca-gha", "--platform", ns.platform, "--trigger-branch", branch, "-d", "./recipes", - "--batch_size", ns.batch_size], d) + # GitHub refuses workflow files over 500 KiB, which a full rebuild's many batches can + # reach (jazzy's win-64 at 25): then retry with larger, hence fewer, batches. + batch_size = int(ns.batch_size) + while True: + rc, output = run_tee(["vinca-gha", "--platform", ns.platform, "--trigger-branch", branch, "-d", + "./recipes", "--batch_size", str(batch_size)], d) + if not rc or WORKFLOW_SIZE_MESSAGE not in output or batch_size >= MAX_BATCH_SIZE: + break + batch_size = min(batch_size * 3 // 2, MAX_BATCH_SIZE) + print(f"The workflow is too large; retrying with --batch_size {batch_size}", flush=True) if rc: return rc # Edit the text: a YAML round trip would turn the `on:` key into `true:` (YAML 1.1). diff --git a/tools/tests/test_abi_check.py b/tools/tests/test_abi_check.py index cf6ed388..7b0cdaba 100644 --- a/tools/tests/test_abi_check.py +++ b/tools/tests/test_abi_check.py @@ -44,10 +44,10 @@ def test_summary_puts_the_snippet_under_the_table(): "ok": {"verdict": "compatible", "old": "1", "new": "2", "libraries": {}, "removed_libraries": [], "headers": [], "pins": []}} text = "\n".join(abi_check.pr_summary(results, "jazzy", "linux-64", ["https://x/test", "https://x/jazzy"], 26)) - assert text.index("| foo |") < text.index("bar:\n build_number: 26") < text.index("
") + assert text.index("| foo |") < text.index("bar:\n build_number: 26") < text.index("
", 1) assert "https://x/test/linux-64 and https://x/jazzy/linux-64" in text - # one section per distribution, open (with the count in the summary) when dependents need a rebuild - assert text.startswith("
jazzy linux-64: **1 need their dependents rebuilt**, " + # one collapsed section per distribution, the count of breaking changes in its summary + assert text.startswith("
jazzy linux-64: **1 need their dependents rebuilt**, " "1 can be bumped on their own") assert text.rstrip().endswith("
") quiet = "\n".join(abi_check.pr_summary({"ok": results["ok"]}, "jazzy", "linux-64", "https://x/jazzy", 26)) diff --git a/tools/tests/test_bot_commands.py b/tools/tests/test_bot_commands.py index a38b39fd..67442862 100644 --- a/tools/tests/test_bot_commands.py +++ b/tools/tests/test_bot_commands.py @@ -112,8 +112,8 @@ def test_merge_build_numbers_keeps_other_keys(tmp_path): def test_rebuild_dependents_from_a_fork_replies_with_the_entries(monkeypatch): - monkeypatch.setenv("GITHUB_REPOSITORY", "RoboStack/robostack-distros") - pull = {"state": "open", "head": {"ref": "main", "repo": {"full_name": "someone/robostack-distros"}}} + monkeypatch.setenv("GITHUB_REPOSITORY", "RoboStack/robostack") + pull = {"state": "open", "head": {"ref": "main", "repo": {"full_name": "someone/robostack"}}} def gh(args): if any(a.endswith("/comments") for a in args): diff --git a/tools/tests/test_generate_gha.py b/tools/tests/test_generate_gha.py new file mode 100644 index 00000000..085c85e2 --- /dev/null +++ b/tools/tests/test_generate_gha.py @@ -0,0 +1,33 @@ +"""rs gha: larger batches when the generated workflow is too large for GitHub.""" + +import robostack as rs + + +def test_gha_retries_with_larger_batches_when_the_workflow_is_too_large(monkeypatch, tmp_path): + sizes = [] + + def fake_run_tee(cmd, cwd): + sizes.append(int(cmd[cmd.index("--batch_size") + 1])) + if sizes[-1] < 50: + return 1, b"RuntimeError: Generated workflow win.yml is 530.8 KiB, exceeding the 500 KiB limit." + return 0, b"" + + monkeypatch.setattr(rs, "run_tee", fake_run_tee) + monkeypatch.setattr(rs, "work_dir", lambda distro: tmp_path) + + assert rs.generate_gha("jazzy", ["--platform", "win-64", "--batch-size", "25"]) == 0 + assert sizes == [25, 37, 55] + + +def test_gha_does_not_retry_other_failures(monkeypatch, tmp_path): + sizes = [] + + def fake_run_tee(cmd, cwd): + sizes.append(int(cmd[cmd.index("--batch_size") + 1])) + return 1, b"some other error" + + monkeypatch.setattr(rs, "run_tee", fake_run_tee) + monkeypatch.setattr(rs, "work_dir", lambda distro: tmp_path) + + assert rs.generate_gha("jazzy", ["--platform", "win-64"]) == 1 + assert sizes == [25]