3939 default : " "
4040
4141concurrency :
42- group : ${{ github.workflow }}-${{ github.ref }}
42+ group : ${{ github.workflow }}-${{ github.event.pull_request.number || github. ref }}-${{ github.event.label.name || 'main' }}-${{ github.event_name }}
4343 cancel-in-progress : true
4444
4545jobs :
@@ -291,16 +291,50 @@ jobs:
291291 build-ref : ${{ needs.pre-flight.outputs.test_sha }}
292292 image-name : ${{ vars.CI_CONTAINER_NAME }}
293293 dockerfile : docker/Dockerfile
294- runner : ${{ needs.org-member-pre-flight.outputs.runner_prefix }} -gpu-x2
294+ runner : ${{ contains( needs.org-member-pre-flight.outputs.runner_prefix, 'azure') && format('{0} -gpu-x2', needs.org-member-pre-flight.outputs.runner_prefix) || contains(needs.org-member-pre-flight.outputs.runner_prefix, 'gcp') && format('{0}-gpu-x4', needs.org-member-pre-flight.outputs.runner_prefix) }}
295295 image-label : ${{ vars.CI_CONTAINER_NAME }}
296296 target : release
297297 registry : ${{ needs.org-member-pre-flight.outputs.registry }}
298298 build-contexts : |
299299 nemo-rl=${{ github.run_id }}/
300+ ${{ vars.UV_BUILD_CACHE == 'enabled' && format('uv-cache-seed=docker-image://{0}/{1}-uv-cache:latest', needs.org-member-pre-flight.outputs.registry, vars.CI_CONTAINER_NAME) || '' }}
300301 build-args : |
301302 MAX_JOBS=4
302303 NEMO_RL_COMMIT=${{ needs.pre-flight.outputs.test_sha }}
303304
305+ update-uv-cache :
306+ name : Update uv build cache
307+ needs : [build-container, org-member-pre-flight]
308+ if : >-
309+ ${{
310+ github.ref == 'refs/heads/main' &&
311+ needs.build-container.result == 'success'
312+ }}
313+ runs-on : ${{ format('{0}-gpu-x2', needs.org-member-pre-flight.outputs.runner_prefix) }}
314+ environment : nemo-ci
315+ env :
316+ REGISTRY : ${{ needs.org-member-pre-flight.outputs.registry }}
317+ IMAGE_NAME : ${{ vars.CI_CONTAINER_NAME }}
318+ steps :
319+ - name : Extract and push uv cache image
320+ run : |
321+ set -euo pipefail
322+ SRC="${REGISTRY}/${IMAGE_NAME}:${{ github.run_id }}"
323+ DST="${REGISTRY}/${IMAGE_NAME}-uv-cache:latest"
324+
325+ docker pull "${SRC}"
326+ CID=$(docker create "${SRC}" true)
327+ mkdir -p /tmp/uv-cache
328+ docker cp "${CID}:/root/.cache/uv/." /tmp/uv-cache/
329+ docker rm "${CID}"
330+
331+ printf 'FROM scratch\nCOPY uv-cache/ /\n' > /tmp/Dockerfile.uv-cache
332+ docker build -t "${DST}" -f /tmp/Dockerfile.uv-cache /tmp
333+ docker push "${DST}"
334+
335+ docker rmi "${SRC}" "${DST}" 2>/dev/null || true
336+ rm -rf /tmp/uv-cache /tmp/Dockerfile.uv-cache
337+
304338 cicd-doc-tests :
305339 strategy :
306340 fail-fast : false
@@ -480,6 +514,24 @@ jobs:
480514 SUMMARY=$(echo $JOB_RESULTS | jq 'to_entries[] | .key + ": " + .value.result' | tr -d '"')
481515 echo '🤖: CICD Result for test level: ${{ needs.pre-flight.outputs.test_level }}' >> $GITHUB_STEP_SUMMARY
482516 echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY
517+
518+ if [[ "$TEST_LEVEL" == "none" ]]; then
519+ echo "" >> $GITHUB_STEP_SUMMARY
520+ echo "---" >> $GITHUB_STEP_SUMMARY
521+ echo "⚠️ **No tests were run.** This PR does not have a CI label." >> $GITHUB_STEP_SUMMARY
522+ echo "" >> $GITHUB_STEP_SUMMARY
523+ echo "To trigger tests, add one of the following labels to your PR:" >> $GITHUB_STEP_SUMMARY
524+ echo "| Label | What it runs |" >> $GITHUB_STEP_SUMMARY
525+ echo "|-------|-------------|" >> $GITHUB_STEP_SUMMARY
526+ echo "| \`CI:docs\` | Doc tests only |" >> $GITHUB_STEP_SUMMARY
527+ echo "| \`CI:Lfast\` | Fast subset (reuses main container) |" >> $GITHUB_STEP_SUMMARY
528+ echo "| \`CI:L0\` | Unit tests + docs + lint |" >> $GITHUB_STEP_SUMMARY
529+ echo "| \`CI:L1\` | L0 + functional tests |" >> $GITHUB_STEP_SUMMARY
530+ echo "| \`CI:L2\` | L1 + convergence tests |" >> $GITHUB_STEP_SUMMARY
531+ echo "" >> $GITHUB_STEP_SUMMARY
532+ echo "This check will remain failed until a CI label is added." >> $GITHUB_STEP_SUMMARY
533+ fi
534+
483535 test "$ALL_SUCCESS" = "true" || test "$CI_SKIP" = "true"
484536
485537 notify-nightly-failure :
@@ -519,19 +571,25 @@ jobs:
519571 matrix :
520572 flag : [doc-test, unit-test, e2e]
521573 steps :
574+ - name : Get PR info
575+ id : get-pr-info
576+ if : startsWith(github.ref, 'refs/heads/pull-request/')
577+ uses : nv-gha-runners/get-pr-info@main
578+
522579 - name : Checkout
523580 uses : actions/checkout@v6
524581
525582 - name : Download coverage reports of current branch
526583 uses : actions/download-artifact@v7
527584 with :
528585 pattern : coverage-${{ matrix.flag }}-*
586+ path : coverage-downloads
529587
530588 - name : Check if artifacts were downloaded
531589 id : check-artifacts
532590 run : |
533- # Check if any coverage directories were downloaded
534- if ls coverage-* 1> /dev/null 2>&1 ; then
591+ # Check if any . coverage files were downloaded
592+ if find coverage-downloads -name ".coverage" -type f 2> /dev/null | grep -q . ; then
535593 echo "artifacts-found=true" >> $GITHUB_OUTPUT
536594 echo "Found coverage artifacts for ${{ matrix.flag }}"
537595 else
@@ -545,12 +603,10 @@ jobs:
545603 run : |
546604 pip install coverage
547605
548- ls -al .
549- ls -al coverage-*/
550- coverage combine --keep $(ls coverage-*/.coverage)
606+ find coverage-downloads -name ".coverage" -type f
607+ coverage combine --keep $(find coverage-downloads -name ".coverage" -type f)
551608 coverage report -i --show-missing
552- rm -rf coverage-*
553- ls -al
609+ rm -rf coverage-downloads
554610
555611 - name : Skip coverage processing
556612 if : ${{ steps.check-artifacts.outputs.artifacts-found == 'false' }}
@@ -564,6 +620,7 @@ jobs:
564620 token : ${{ secrets.CODECOV_TOKEN }}
565621 verbose : true
566622 flags : ${{ matrix.flag }}
623+ base_sha : ${{ fromJSON(steps.get-pr-info.outputs.pr-info || '{}').base.sha }}
567624
568625 - name : Upload artifacts
569626 if : ${{ steps.check-artifacts.outputs.artifacts-found == 'true' }}
0 commit comments