Repository navigation
CI: pixi lockfile refresh #16
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 | |
| # Scheduled (and on-demand) pixi lockfile refresh. All workspaces are updated | |
| # in one job and, when anything changes, one PR. See #2298 and #2849. | |
| name: "CI: pixi lockfile refresh" | |
| on: | |
| schedule: | |
| # Monday 03:17 Eastern. GitHub handles the DST offset for the IANA zone, | |
| # and a non-zero minute avoids the start-of-hour window where GitHub | |
| # documents scheduled runs being delayed or dropped. | |
| - cron: "17 3 * * 1" | |
| timezone: "America/New_York" | |
| workflow_dispatch: {} | |
| defaults: | |
| run: | |
| shell: bash --noprofile --norc -xeuo pipefail {0} | |
| permissions: {} | |
| jobs: | |
| refresh: | |
| name: pixi update (all workspaces) | |
| if: ${{ github.repository_owner == 'nvidia' }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 195 | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| concurrency: | |
| group: pixi-lock-refresh | |
| cancel-in-progress: false | |
| steps: | |
| - name: Checkout ${{ github.event.repository.name }} | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| # Full history and tags for package metadata, without historical | |
| # file contents. See ci/README.md for the checkout policy. | |
| fetch-depth: 0 | |
| filter: blob:none | |
| ref: ${{ github.event.repository.default_branch }} | |
| - name: Setup pixi | |
| id: setup-pixi | |
| uses: ./.github/actions/setup-pixi | |
| # Pixi 0.73.0's update and lock-read paths can serialize the same solve | |
| # differently (#2804). Canonicalize with the same operation used by the | |
| # freshness workflow before opening the PR. If cuda_core hits the exact | |
| # samples-source pruning defect guarded there, retain its committed lock | |
| # and continue refreshing the other workspaces. | |
| - name: Update and canonicalize all lockfiles | |
| id: update | |
| env: | |
| PIXI_VERSION: ${{ steps.setup-pixi.outputs.pixi-version }} | |
| WORKSPACE_TIMEOUT: 30m | |
| run: | | |
| workspaces="$(python3 ci/tools/list_pixi_workspaces.py)" | |
| workspace_rows="$( | |
| jq -ce ' | |
| if type != "array" or length == 0 then | |
| error("workspace inventory must be a non-empty array") | |
| elif any(.[]; | |
| type != "object" | |
| or (.manifest | type != "string") | |
| or (.lockfile | type != "string") | |
| or .manifest == "" | |
| or .lockfile == "" | |
| ) then | |
| error("each workspace must have non-empty string manifest and lockfile fields") | |
| else | |
| .[] | |
| end | |
| ' <<<"${workspaces}" | |
| )" | |
| while IFS= read -r workspace; do | |
| manifest="$(jq -r '.manifest' <<<"${workspace}")" | |
| lockfile="$(jq -r '.lockfile' <<<"${workspace}")" | |
| echo "::group::pixi update (${manifest})" | |
| workspace_status=0 | |
| # The single-quoted script expands its variables in the child shell. | |
| # shellcheck disable=SC2016 | |
| timeout --kill-after=1m "${WORKSPACE_TIMEOUT}" \ | |
| bash --noprofile --norc -xeuo pipefail -c ' | |
| manifest="$1" | |
| lockfile="$2" | |
| pixi_version="$3" | |
| committed_blob="$(git hash-object "${lockfile}")" | |
| pixi update --no-install --manifest-path "${manifest}" | |
| # The detector reads this uncommitted post-update state through | |
| # git cat-file, so explicitly persist the blob in the runner-local | |
| # temporary object database. | |
| updated_blob="$(git hash-object -w "${lockfile}")" | |
| check_status=0 | |
| pixi lock --check --manifest-path "${manifest}" \ | |
| || check_status=$? | |
| if ((check_status != 0)); then | |
| defect_status=1 | |
| if [[ "${manifest}" == "cuda_core" ]]; then | |
| defect_status=0 | |
| python3 ci/tools/check_pixi_samples_source_pruning.py \ | |
| --original-blob "${updated_blob}" \ | |
| --lockfile "${lockfile}" \ | |
| --manifest-path "${manifest}/pixi.toml" \ | |
| --pixi-version "${pixi_version}" \ | |
| --check-status "${check_status}" \ | |
| || defect_status=$? | |
| fi | |
| if ((defect_status == 0)); then | |
| echo "::warning title=Known Pixi samples lockfile bug::Pixi ${pixi_version} removed only the nine samples local-source references after updating ${lockfile}. Keeping the committed cuda_core lockfile and continuing with the other workspaces; all other refresh failures remain strict." | |
| git cat-file blob "${committed_blob}" > "${lockfile}" | |
| echo "known-defect-skipped=true" >> "${GITHUB_OUTPUT}" | |
| exit 0 | |
| elif [[ "${manifest}" == "cuda_core" ]] && ((defect_status != 1)); then | |
| echo "::error::Could not determine whether ${lockfile} matches the known Pixi samples-source pruning defect. Resolve the detector error above and rerun." | |
| exit "${defect_status}" | |
| fi | |
| exit "${check_status}" | |
| fi | |
| canonical_blob="$(git hash-object "${lockfile}")" | |
| verify_status=0 | |
| pixi lock --check --manifest-path "${manifest}" \ | |
| || verify_status=$? | |
| verified_blob="$(git hash-object "${lockfile}")" | |
| if ((verify_status != 0)) || [[ "${canonical_blob}" != "${verified_blob}" ]]; then | |
| echo "::error::pixi ${pixi_version} did not reach a successful byte-stable check for ${lockfile} (verification exit ${verify_status}, canonical blob ${canonical_blob}, verified blob ${verified_blob}); refusing to open an unstable refresh PR." | |
| exit 1 | |
| fi | |
| ' bash "${manifest}" "${lockfile}" "${PIXI_VERSION}" \ | |
| || workspace_status=$? | |
| if ((workspace_status == 124 || workspace_status == 137)); then | |
| echo "::error::Timed out after ${WORKSPACE_TIMEOUT} while refreshing '${manifest}'." | |
| elif ((workspace_status != 0)); then | |
| echo "::error::Failed to refresh '${manifest}' (exit ${workspace_status})." | |
| fi | |
| echo "::endgroup::" | |
| if ((workspace_status != 0)); then | |
| exit "${workspace_status}" | |
| fi | |
| done <<<"${workspace_rows}" | |
| { | |
| echo "lockfiles<<EOF" | |
| jq -r '.[].lockfile' <<<"${workspaces}" | |
| echo "EOF" | |
| } >> "${GITHUB_OUTPUT}" | |
| - name: Compose PR body | |
| id: pr-body | |
| env: | |
| KNOWN_DEFECT_SKIPPED: ${{ steps.update.outputs.known-defect-skipped }} | |
| PIXI_VERSION: ${{ steps.setup-pixi.outputs.pixi-version }} | |
| run: | | |
| body_path="${RUNNER_TEMP}/pixi-lock-refresh-body.md" | |
| { | |
| echo "Automated lockfile refresh using pixi" \ | |
| "\`${PIXI_VERSION}\` (\`pixi update --no-install\`, followed by" \ | |
| "byte-stable \`pixi lock --check\` canonicalization for each" \ | |
| "refreshed workspace)." | |
| if [[ "${KNOWN_DEFECT_SKIPPED}" == "true" ]]; then | |
| echo | |
| echo "> [!NOTE]" | |
| echo "> \`cuda_core/pixi.lock\` was left unchanged because Pixi" \ | |
| "\`${PIXI_VERSION}\` reproduced the exact known samples-source" \ | |
| "pruning defect. Other workspaces were refreshed normally." | |
| fi | |
| echo | |
| echo "Lockfiles covered by the refresh:" | |
| python3 ci/tools/list_pixi_workspaces.py \ | |
| | jq -r '.[] | "- `\(.lockfile)`"' | |
| echo | |
| echo "See #2298 and #2849." | |
| echo | |
| echo "> [!IMPORTANT]" | |
| echo "> This PR was opened with \`GITHUB_TOKEN\`. A maintainer with write access must:" | |
| echo ">" | |
| echo "> 1. Select **Approve workflows to run** in the merge box." | |
| echo "> 2. Assign themselves to this PR. The human-generated \`assigned\` event" | |
| echo "> creates the required **PR has assignee, labels, and milestone** check" | |
| echo "> and gives the PR a clear owner." | |
| echo | |
| echo "If the diff looks wrong, close this PR and leave the branch deleted; the" | |
| echo "next scheduled run opens a fresh one if an update is still needed." | |
| } > "${body_path}" | |
| echo "path=${body_path}" >> "${GITHUB_OUTPUT}" | |
| - name: Open or update a lockfile-only PR | |
| id: cpr | |
| uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 | |
| with: | |
| token: ${{ github.token }} | |
| add-paths: ${{ steps.update.outputs.lockfiles }} | |
| commit-message: "chore: refresh pixi lockfiles" | |
| signoff: true | |
| sign-commits: true | |
| branch: ci/pixi-lock-refresh/all | |
| delete-branch: true | |
| title: "chore: refresh pixi lockfiles" | |
| labels: | | |
| CI/CD | |
| dependencies | |
| body-path: ${{ steps.pr-body.outputs.path }} | |
| author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> | |
| committer: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> | |
| - name: Warn about required maintainer action | |
| if: ${{ steps.cpr.outputs.pull-request-operation == 'created' || steps.cpr.outputs.pull-request-operation == 'updated' }} | |
| run: echo "::warning::The refresh PR requires a maintainer to approve its workflow runs and assign themselves to create the required metadata check." | |
| - name: Summarize | |
| run: | | |
| { | |
| echo "### pixi lock refresh (all workspaces)" | |
| echo "" | |
| echo "- Operation: \`${{ steps.cpr.outputs.pull-request-operation }}\`" | |
| if [ -n "${{ steps.cpr.outputs.pull-request-url }}" ]; then | |
| echo "- PR: ${{ steps.cpr.outputs.pull-request-url }}" | |
| else | |
| echo "- No lockfile diff; PR not opened." | |
| fi | |
| if [[ "${{ steps.update.outputs.known-defect-skipped }}" == "true" ]]; then | |
| echo "- \`cuda_core/pixi.lock\` retained its committed state because the exact known Pixi samples-source pruning defect was detected." | |
| fi | |
| } >> "$GITHUB_STEP_SUMMARY" |