Complete JetPack 7.2.1 migration and port Orin fast boot #264
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: | |
| validation: | |
| runs-on: ubuntu-22.04 | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install validation tools | |
| run: sudo apt-get update -qq && sudo apt-get install -y device-tree-compiler gcc patch | |
| - name: Validate build and fast-boot helpers | |
| run: sudo python3 -m unittest discover -s scripts -p 'test_*.py' | |
| ark_os_noble: | |
| # Only release tags provision an application; ordinary PR/main builds keep | |
| # their kernel-only path. Native ARM64 avoids a multi-hour emulated build. | |
| if: startsWith(github.ref, 'refs/tags/') | |
| runs-on: ubuntu-24.04-arm | |
| timeout-minutes: 180 | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| persist-credentials: false | |
| - name: Free application build 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: Build pinned Noble application natively | |
| run: | | |
| test "$(uname -m)" = aarch64 | |
| ./scripts/build_ark_os_noble.sh "$RUNNER_TEMP/ark-os-noble-build" | |
| - name: Share Noble package and build provenance | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ark-os-noble | |
| path: | | |
| downloads/ark-os-jetson-noble_*_arm64.deb | |
| downloads/ark-os-jetson-noble_*_arm64.build.json | |
| if-no-files-found: error | |
| compression-level: 0 | |
| overwrite: true | |
| build: | |
| needs: [validation, ark_os_noble] | |
| # Validation gates every build. A skipped release-only application job must | |
| # not skip PR/main compile checks; releases also require that artifact. | |
| if: ${{ !cancelled() && needs.validation.result == 'success' && (!startsWith(github.ref, 'refs/tags/') || needs.ark_os_noble.result == 'success') }} | |
| 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: | |
| # Keep the /mnt staging symlink reachable after R39 container handoff. | |
| ARK_STAGING_MOUNT: /mnt/staging | |
| 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 cross 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" | |
| echo "version=$VERSION" | |
| 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 cross 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 Noble application artifact | |
| if: startsWith(github.ref, 'refs/tags/') | |
| uses: actions/download-artifact@v5 | |
| with: | |
| name: ark-os-noble | |
| path: downloads | |
| - name: Verify Noble application provenance | |
| if: startsWith(github.ref, 'refs/tags/') | |
| run: | | |
| source versions.env | |
| python3 - "$ARK_OS_VERSION" "$ARK_OS_SOURCE_COMMIT" <<'PYTHON' | |
| import hashlib, json, pathlib, sys | |
| package = pathlib.Path("downloads") / f"ark-os-jetson-noble_{sys.argv[1]}_arm64.deb" | |
| metadata = json.loads(package.with_suffix(".build.json").read_text()) | |
| digest = hashlib.sha256() | |
| with package.open("rb") as stream: | |
| for chunk in iter(lambda: stream.read(1024 * 1024), b""): | |
| digest.update(chunk) | |
| if metadata["package"] != package.name or metadata["source_commit"] != sys.argv[2]: | |
| raise SystemExit("Noble artifact does not match the pinned source/version") | |
| if metadata["sha256"] != digest.hexdigest(): | |
| raise SystemExit("Noble artifact checksum mismatch") | |
| print(f"Verified {package.name}: {digest.hexdigest()}") | |
| PYTHON | |
| - name: Download BSP | |
| run: ./setup.sh --force | |
| - name: Reset ccache stats | |
| run: ccache -z | |
| - name: Build kernel | |
| # Release tags consume the pinned Noble artifact built above, then | |
| # provision ARK-OS and the native R39 camera stack into the image. Missing | |
| # or incompatible artifacts fail; no other release or OS is substituted. | |
| # The draft release ships the resulting provisioned image. PR/main builds | |
| # use --no-provision to retain the existing kernel compile-check path. | |
| 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[@]}" |