fix(build): derive the toolchain dir from versions.env and check it b… #247
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
| name: Build | |
| on: | |
| push: | |
| branches: [main] | |
| tags: | |
| - 'pab-[0-9]*' | |
| - 'jaj-[0-9]*' | |
| - 'pab-v3-[0-9]*' | |
| pull_request: | |
| concurrency: | |
| group: build-${{ github.ref }} | |
| cancel-in-progress: ${{ !startsWith(github.ref, 'refs/tags/') }} | |
| jobs: | |
| build: | |
| runs-on: ubuntu-22.04 | |
| # Kernel build alone is ~70 min on a cold ccache; leave headroom for packaging | |
| # (tar + parallel compress of the rootfs) and the multi-GB release upload. | |
| timeout-minutes: 180 | |
| permissions: | |
| contents: write | |
| env: | |
| CCACHE_DIR: ${{ github.workspace }}/.ccache | |
| # Above one build's object set (~1 GB) so ccache doesn't evict its own hits; | |
| # the rotating ccache is the natural LRU victim under the repo's 10 GB budget. | |
| CCACHE_MAXSIZE: "2G" | |
| # Fresh checkouts reset mtimes and a few kernel files embed __DATE__/__TIME__; | |
| # ignore those so they don't force misses. | |
| CCACHE_SLOPPINESS: time_macros,include_file_ctime,include_file_mtime | |
| # The bootlin toolchain is restored from its own cache each run with fresh | |
| # mtimes; ccache's default compiler check is the compiler's mtime, so that alone | |
| # invalidated the entire cache (observed ~1% hit rate). Hash the compiler's | |
| # contents instead so hits survive a toolchain cache restore. | |
| CCACHE_COMPILERCHECK: content | |
| steps: | |
| - name: Parse tag | |
| if: startsWith(github.ref, 'refs/tags/') | |
| id: tag | |
| run: | | |
| TAG="${GITHUB_REF_NAME}" | |
| case "$TAG" in | |
| pab-v3-*) PRODUCT="pab-v3"; VERSION="${TAG#pab-v3-}"; TARGET="PAB_V3" ;; | |
| pab-*) PRODUCT="pab"; VERSION="${TAG#pab-}"; TARGET="PAB" ;; | |
| jaj-*) PRODUCT="jaj"; VERSION="${TAG#jaj-}"; TARGET="JAJ" ;; | |
| *) echo "::error::Unrecognized tag format: $TAG"; exit 1 ;; | |
| esac | |
| echo "product=$PRODUCT" >> "$GITHUB_OUTPUT" | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "target=$TARGET" >> "$GITHUB_OUTPUT" | |
| echo "Parsed tag: product=$PRODUCT version=$VERSION target=$TARGET" | |
| - uses: actions/checkout@v4 | |
| - name: Free disk space | |
| uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be | |
| with: | |
| tool-cache: true | |
| android: true | |
| dotnet: true | |
| haskell: true | |
| large-packages: true | |
| docker-images: true | |
| swap-storage: false | |
| - name: Stage build tree on /mnt | |
| # staging/ (extracted rootfs + massflash images + the multi-GB mfi tarball) | |
| # overran the ~49 GB free on / and crashed the runner with ENOSPC during | |
| # packaging. The ephemeral /mnt has ~65 GB free and is otherwise unused, so | |
| # build there. The final package + split stay in the workspace on /, where | |
| # the release step globs for them. | |
| run: | | |
| sudo mkdir -p /mnt/staging | |
| sudo chown "$(id -u):$(id -g)" /mnt/staging | |
| ln -s /mnt/staging staging | |
| - name: Install prerequisites | |
| env: | |
| DEBIAN_FRONTEND: noninteractive | |
| run: | | |
| sudo -E apt-get update -qq | |
| sudo -E apt-get install -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" \ | |
| abootimg binfmt-support binutils ccache cpio cpp curl \ | |
| device-tree-compiler dosfstools \ | |
| iproute2 iputils-ping lbzip2 libxml2-utils lz4 \ | |
| netcat-openbsd nfs-kernel-server openssl \ | |
| pigz python3-yaml qemu-user-static rsync sshpass \ | |
| udev usbutils uuid-runtime whois xmlstarlet zstd | |
| - name: Resolve cache keys from versions.env | |
| id: cachekeys | |
| run: | | |
| source versions.env | |
| echo "bsp=${EXPECTED_BSP_RELEASE}.${EXPECTED_BSP_REVISION}" >> "$GITHUB_OUTPUT" | |
| echo "toolchain=$(basename "$TOOLCHAIN_URL")" >> "$GITHUB_OUTPUT" | |
| - name: Cache bootlin toolchain | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/l4t-gcc | |
| key: l4t-gcc-${{ steps.cachekeys.outputs.toolchain }} | |
| # The L4T BSP/rootfs/sources tarballs (~2.7 GB) are pinned by BSP version, so | |
| # cache them on it — setup.sh skips any tarball already present in downloads/. | |
| - name: Cache L4T BSP tarballs | |
| uses: actions/cache@v4 | |
| with: | |
| path: downloads/*.tbz2 | |
| key: l4t-bsp-${{ steps.cachekeys.outputs.bsp }} | |
| # ccache across runs (kernel C is mostly hits). Rotating per-run key so each | |
| # run saves an updated cache; restore-keys pulls the most recent prior one. | |
| - name: Cache ccache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ${{ github.workspace }}/.ccache | |
| key: ccache-${{ steps.cachekeys.outputs.bsp }}-${{ github.run_id }} | |
| restore-keys: | | |
| ccache-${{ steps.cachekeys.outputs.bsp }}- | |
| - name: Download BSP | |
| run: ./setup.sh --force | |
| - name: Reset ccache stats | |
| run: ccache -z | |
| - name: Build kernel | |
| # Provisioning (ARK-OS + the pinned camera stack) is the build default now; | |
| # tag builds keep --provision explicit for clarity. provision.sh falls back | |
| # loudly to the newest published (pre)release if the pin isn't published. The | |
| # draft release ships a flashable, provisioned image; promoting it to published | |
| # is a GitHub toggle with no rebuild. PR/main builds only compile-check, so | |
| # --no-provision skips the ~6 min provision and its NVIDIA/GitHub network deps. | |
| run: | | |
| if [ -n "${{ steps.tag.outputs.target }}" ]; then | |
| ./build.sh ${{ steps.tag.outputs.target }} --provision | |
| else | |
| ./build.sh PAB --no-provision | |
| fi | |
| - name: ccache stats | |
| if: always() | |
| run: ccache -s | |
| - name: Generate flash package | |
| if: startsWith(github.ref, 'refs/tags/') | |
| run: ./packaging/generate_flash_package.sh ${{ steps.tag.outputs.target }} | |
| - name: Create release | |
| if: startsWith(github.ref, 'refs/tags/') | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| TAG="${GITHUB_REF_NAME}" | |
| PRODUCT="${{ steps.tag.outputs.product }}" | |
| VERSION="${{ steps.tag.outputs.version }}" | |
| source versions.env | |
| L4T_VERSION="${EXPECTED_BSP_RELEASE}.${EXPECTED_BSP_REVISION}" | |
| PRODUCT_UPPER=$(echo "$PRODUCT" | tr '[:lower:]' '[:upper:]' | tr '-' '_') | |
| RELEASE_FILES=() | |
| for f in ark-*.tar.gz; do | |
| [ -f "$f" ] && RELEASE_FILES+=("$f") | |
| done | |
| for d in ark-*_split; do | |
| [ -d "$d" ] || continue | |
| for part in "$d"/*.part.*; do | |
| [ -f "$part" ] && RELEASE_FILES+=("$part") | |
| done | |
| done | |
| if [ ${#RELEASE_FILES[@]} -eq 0 ]; then | |
| echo "::error::No flash package artifacts found (ark-*.tar.gz or ark-*_split/)" | |
| exit 1 | |
| fi | |
| # The flasher isn't a release asset; it's served from main (linked in the notes below). | |
| echo "Release assets:" | |
| for f in "${RELEASE_FILES[@]}"; do | |
| echo " $(basename "$f") ($(du -h "$f" | cut -f1))" | |
| done | |
| COMMIT_SHORT=$(git rev-parse --short HEAD) | |
| cat > /tmp/release-notes.md <<EOF | |
| ## ${PRODUCT_UPPER} v${VERSION} | |
| L4T ${L4T_VERSION} (Jetpack ${JETPACK_VERSION}) | Built from \`${COMMIT_SHORT}\` | |
| ### Flash | |
| Fetch the flasher from the main branch (it flashes any release): | |
| \`\`\` | |
| curl -LO https://raw.githubusercontent.com/${GITHUB_REPOSITORY}/main/packaging/flash_from_package.sh | |
| chmod +x flash_from_package.sh | |
| ./flash_from_package.sh ${TAG} | |
| \`\`\` | |
| Put the Jetson in recovery mode before running. Requires a Debian/Ubuntu host with USB connection. Supports all Orin Nano/NX module variants. | |
| EOF | |
| # Every release is born a hidden draft; promoting it to published is a | |
| # manual GitHub toggle (same artifact, same tag — no rebuild, no rename). | |
| gh release create "$TAG" --draft \ | |
| --title "${PRODUCT_UPPER} v${VERSION}" \ | |
| --notes-file /tmp/release-notes.md \ | |
| "${RELEASE_FILES[@]}" |