Create SD Card & eMMC Images #59
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: Create SD Card & eMMC Images | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| board: | |
| description: 'Board to create image for' | |
| type: choice | |
| required: true | |
| options: | |
| - raspberrypi-rpi64 | |
| - bananapi-bpi-r3 | |
| - friendlyarm-nanopi-r2s | |
| default: 'raspberrypi-rpi64' | |
| use_latest_release: | |
| description: 'Use latest release artifacts instead of workflow artifacts' | |
| type: boolean | |
| default: false | |
| jobs: | |
| create-image: | |
| name: Create SD Card Image for ${{ inputs.board }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| clean: true | |
| fetch-depth: 0 | |
| submodules: recursive | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| genimage \ | |
| u-boot-tools \ | |
| parted \ | |
| gdisk \ | |
| qemu-utils \ | |
| dosfstools \ | |
| e2fsprogs \ | |
| genext2fs \ | |
| mtools \ | |
| jq | |
| - name: Prepare build environment | |
| run: | | |
| # Set up directory structure similar to buildroot build | |
| mkdir -p output/images | |
| mkdir -p build | |
| - name: Set bootloader and target based on board | |
| run: | | |
| case "${{ inputs.board }}" in | |
| raspberrypi-rpi64) | |
| echo "BOOTLOADER=rpi64_boot" >> $GITHUB_ENV | |
| echo "TARGET=aarch64" >> $GITHUB_ENV | |
| echo "BUILD_EMMC=false" >> $GITHUB_ENV | |
| ;; | |
| bananapi-bpi-r3) | |
| echo "BOOTLOADER_SD=bpi_r3_sd_boot" >> $GITHUB_ENV | |
| echo "BOOTLOADER_EMMC=bpi_r3_emmc_boot" >> $GITHUB_ENV | |
| echo "TARGET=aarch64" >> $GITHUB_ENV | |
| echo "BUILD_EMMC=true" >> $GITHUB_ENV | |
| ;; | |
| friendlyarm-nanopi-r2s) | |
| echo "BOOTLOADER=nanopi_r2s_boot" >> $GITHUB_ENV | |
| echo "TARGET=aarch64" >> $GITHUB_ENV | |
| echo "BUILD_EMMC=false" >> $GITHUB_ENV | |
| ;; | |
| *) | |
| echo "Error: Unknown board ${{ inputs.board }}" | |
| exit 1 | |
| ;; | |
| esac | |
| echo "Target: $TARGET for board: ${{ inputs.board }}" | |
| if [ "$BUILD_EMMC" = "true" ]; then | |
| echo "Building both SD and eMMC images" | |
| echo "SD Bootloader: $BOOTLOADER_SD" | |
| echo "eMMC Bootloader: $BOOTLOADER_EMMC" | |
| else | |
| echo "Building SD image only" | |
| echo "Bootloader: $BOOTLOADER" | |
| fi | |
| - name: Download bootloader artifacts | |
| if: ${{ !inputs.use_latest_release }} | |
| run: | | |
| # Download from latest bootloader build workflow on main branch | |
| gh run list --workflow=build-boot.yml --branch=main --limit=1 --status=success --json databaseId --jq '.[0].databaseId' > latest_boot_run_id | |
| BOOT_RUN_ID=$(cat latest_boot_run_id) | |
| if [ "$BUILD_EMMC" = "true" ]; then | |
| # Download both SD and eMMC bootloaders for boards that support both | |
| echo "Downloading SD bootloader: ${BOOTLOADER_SD}" | |
| gh run download ${BOOT_RUN_ID} --name artifact-${BOOTLOADER_SD} --dir temp_bootloader_sd/ | |
| mkdir -p output_sd/images | |
| cd temp_bootloader_sd/ | |
| tar -xzf *.tar.gz --strip-components=1 -C ../output_sd/images/ | |
| cd ../ | |
| rm -rf temp_bootloader_sd/ | |
| echo "Downloading eMMC bootloader: ${BOOTLOADER_EMMC}" | |
| gh run download ${BOOT_RUN_ID} --name artifact-${BOOTLOADER_EMMC} --dir temp_bootloader_emmc/ | |
| mkdir -p output_emmc/images | |
| cd temp_bootloader_emmc/ | |
| tar -xzf *.tar.gz --strip-components=1 -C ../output_emmc/images/ | |
| cd ../ | |
| rm -rf temp_bootloader_emmc/ | |
| echo "SD bootloader files:" | |
| ls -la output_sd/images/ | |
| echo "eMMC bootloader files:" | |
| ls -la output_emmc/images/ | |
| else | |
| # Single bootloader for boards that only support SD | |
| gh run download ${BOOT_RUN_ID} --name artifact-${BOOTLOADER} --dir temp_bootloader/ | |
| # Extract bootloader directly to output/images | |
| cd temp_bootloader/ | |
| tar -xzf *.tar.gz --strip-components=1 -C ../output/images/ | |
| cd ../ | |
| rm -rf temp_bootloader/ | |
| echo "Bootloader files extracted to output/images:" | |
| ls -la output/images/ | |
| fi | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Download Infix artifacts | |
| if: ${{ !inputs.use_latest_release }} | |
| run: | | |
| # Download from latest Kernelkit Trigger workflow for main branch | |
| gh run list --workflow=164295764 --branch=main --limit=1 --status=success --json databaseId --jq '.[0].databaseId' > latest_infix_run_id | |
| INFIX_RUN_ID=$(cat latest_infix_run_id) | |
| if [ "$BUILD_EMMC" = "true" ]; then | |
| # Copy Infix artifacts to both SD and eMMC output directories | |
| gh run download ${INFIX_RUN_ID} --name artifact-${TARGET} --dir temp_infix/ | |
| cd temp_infix/ | |
| tar -xzf *.tar.gz --strip-components=1 -C ../output_sd/images/ | |
| tar -xzf *.tar.gz --strip-components=1 -C ../output_emmc/images/ | |
| cd ../ | |
| rm -rf temp_infix/ | |
| echo "Infix files extracted to output_sd/images:" | |
| ls -la output_sd/images/ | |
| echo "Infix files extracted to output_emmc/images:" | |
| ls -la output_emmc/images/ | |
| else | |
| # Single output directory for SD-only boards | |
| gh run download ${INFIX_RUN_ID} --name artifact-${TARGET} --dir temp_infix/ | |
| # Extract Infix directly to output/images | |
| cd temp_infix/ | |
| tar -xzf *.tar.gz --strip-components=1 -C ../output/images/ | |
| cd ../ | |
| rm -rf temp_infix/ | |
| echo "Infix files extracted to output/images:" | |
| ls -la output/images/ | |
| fi | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Download from latest releases | |
| if: ${{ inputs.use_latest_release }} | |
| run: | | |
| if [ "$BUILD_EMMC" = "true" ]; then | |
| # Download both SD and eMMC bootloaders | |
| gh release download latest-boot --pattern "*${BOOTLOADER_SD}*" --dir temp_bootloader_sd/ | |
| mkdir -p output_sd/images | |
| cd temp_bootloader_sd/ | |
| tar -xzf *.tar.gz --strip-components=1 -C ../output_sd/images/ | |
| cd ../ | |
| rm -rf temp_bootloader_sd/ | |
| gh release download latest-boot --pattern "*${BOOTLOADER_EMMC}*" --dir temp_bootloader_emmc/ | |
| mkdir -p output_emmc/images | |
| cd temp_bootloader_emmc/ | |
| tar -xzf *.tar.gz --strip-components=1 -C ../output_emmc/images/ | |
| cd ../ | |
| rm -rf temp_bootloader_emmc/ | |
| # Download Infix once and extract to both directories | |
| gh release download latest --pattern "*${TARGET}*" --dir temp_infix/ | |
| cd temp_infix/ | |
| tar -xzf *.tar.gz --strip-components=1 -C ../output_sd/images/ | |
| tar -xzf *.tar.gz --strip-components=1 -C ../output_emmc/images/ | |
| cd ../ | |
| rm -rf temp_infix/ | |
| echo "SD files extracted to output_sd/images:" | |
| ls -la output_sd/images/ | |
| echo "eMMC files extracted to output_emmc/images:" | |
| ls -la output_emmc/images/ | |
| else | |
| # Download latest bootloader release | |
| gh release download latest-boot --pattern "*${BOOTLOADER}*" --dir temp_bootloader/ | |
| cd temp_bootloader/ | |
| tar -xzf *.tar.gz --strip-components=1 -C ../output/images/ | |
| cd ../ | |
| rm -rf temp_bootloader/ | |
| # Download latest Infix release | |
| gh release download latest --pattern "*${TARGET}*" --dir temp_infix/ | |
| cd temp_infix/ | |
| tar -xzf *.tar.gz --strip-components=1 -C ../output/images/ | |
| cd ../ | |
| rm -rf temp_infix/ | |
| echo "All files extracted to output/images:" | |
| ls -la output/images/ | |
| fi | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Verify extracted files | |
| run: | | |
| if [ "$BUILD_EMMC" = "true" ]; then | |
| echo "Files available for SD image:" | |
| ls -la output_sd/images/ | |
| echo "" | |
| echo "Files available for eMMC image:" | |
| ls -la output_emmc/images/ | |
| else | |
| echo "Files available for mkimage.sh:" | |
| ls -la output/images/ | |
| echo "" | |
| echo "File types:" | |
| file output/images/* || true | |
| fi | |
| - name: Create SD card image | |
| run: | | |
| if [ "$BUILD_EMMC" = "true" ]; then | |
| export BINARIES_DIR=$PWD/output_sd/images | |
| export BUILD_DIR=$PWD/build | |
| export BR2_EXTERNAL_INFIX_PATH=$PWD | |
| export RELEASE="" | |
| export INFIX_ID="infix" | |
| ./utils/mkimage.sh -t sdcard ${{ inputs.board }} | |
| else | |
| export BINARIES_DIR=$PWD/output/images | |
| export BUILD_DIR=$PWD/build | |
| export BR2_EXTERNAL_INFIX_PATH=$PWD | |
| export RELEASE="" | |
| export INFIX_ID="infix" | |
| ./utils/mkimage.sh ${{ inputs.board }} | |
| fi | |
| - name: Create eMMC image | |
| if: ${{ env.BUILD_EMMC == 'true' }} | |
| run: | | |
| export BINARIES_DIR=$PWD/output_emmc/images | |
| export BUILD_DIR=$PWD/build | |
| export BR2_EXTERNAL_INFIX_PATH=$PWD | |
| export RELEASE="" | |
| export INFIX_ID="infix" | |
| ./utils/mkimage.sh -t emmc ${{ inputs.board }} | |
| - name: Verify created images | |
| run: | | |
| if [ "$BUILD_EMMC" = "true" ]; then | |
| echo "SD card image:" | |
| ls -lh output_sd/images/*-sdcard.img* 2>/dev/null || true | |
| if ls output_sd/images/*-sdcard.img 1> /dev/null 2>&1; then | |
| for img in output_sd/images/*-sdcard.img; do | |
| echo "- $(basename $img)" | |
| file "$img" | |
| fdisk -l "$img" 2>/dev/null | head -20 | |
| done | |
| fi | |
| echo "" | |
| echo "eMMC image:" | |
| ls -lh output_emmc/images/*-emmc.img* 2>/dev/null || true | |
| if ls output_emmc/images/*-emmc.img 1> /dev/null 2>&1; then | |
| for img in output_emmc/images/*-emmc.img; do | |
| echo "- $(basename $img)" | |
| file "$img" | |
| fdisk -l "$img" 2>/dev/null | head -20 | |
| done | |
| fi | |
| # Copy both images to output/images for artifact upload | |
| mkdir -p output/images | |
| cp output_sd/images/*-sdcard.img* output/images/ 2>/dev/null || true | |
| cp output_emmc/images/*-emmc.img* output/images/ 2>/dev/null || true | |
| else | |
| echo "Contents of output/images after mkimage.sh:" | |
| ls -lh output/images/ | |
| # Look for SD card image with pattern: *-sdcard.img | |
| if ls output/images/*-sdcard.img 1> /dev/null 2>&1; then | |
| echo "Found SD card image(s):" | |
| for img in output/images/*-sdcard.img; do | |
| echo "- $(basename $img)" | |
| file "$img" | |
| fdisk -l "$img" 2>/dev/null || true | |
| done | |
| else | |
| echo "No SD card image found matching pattern: *-sdcard.img" | |
| echo "Available files:" | |
| ls -la output/images/ | |
| exit 1 | |
| fi | |
| fi | |
| - name: Upload images as artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: images-${{ inputs.board }} | |
| path: | | |
| output/images/*-sdcard.img* | |
| output/images/*-emmc.img* | |
| retention-days: 30 | |
| - name: Create checksums | |
| run: | | |
| cd output/images/ | |
| for file in *-sdcard.img *-emmc.img; do | |
| if [ -f "$file" ]; then | |
| sha256sum "$file" > "$file.sha256" | |
| fi | |
| done | |
| - name: Upload to release | |
| uses: ncipollo/release-action@v1 | |
| with: | |
| allowUpdates: true | |
| omitName: true | |
| omitBody: true | |
| omitBodyDuringUpdate: true | |
| prerelease: true | |
| tag: "latest-boot" | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| artifacts: "output/images/*-sdcard.img*,output/images/*-emmc.img*" | |
| - name: Generate summary | |
| run: | | |
| if [ "$BUILD_EMMC" = "true" ]; then | |
| cat <<EOF >> $GITHUB_STEP_SUMMARY | |
| # SD Card & eMMC Image Build Complete! 🚀 | |
| **Board:** ${{ inputs.board }} | |
| **Target:** ${{ env.TARGET }} | |
| **SD Bootloader:** ${{ env.BOOTLOADER_SD }} | |
| **eMMC Bootloader:** ${{ env.BOOTLOADER_EMMC }} | |
| **Artifact Source:** ${{ inputs.use_latest_release && 'Latest Release' || 'Latest Workflow Run' }} | |
| ## Created Images | |
| $(find output/images/ -name "*.img" -o -name "*.img.bmap" | xargs ls -lh 2>/dev/null | awk '{print "- " $9 " (" $5 ")"}' || echo "- No images found") | |
| ## Download | |
| Both SD card and eMMC images are available as workflow artifacts above and in the latest-boot release. | |
| EOF | |
| else | |
| cat <<EOF >> $GITHUB_STEP_SUMMARY | |
| # SD Card Image Build Complete! 🚀 | |
| **Board:** ${{ inputs.board }} | |
| **Target:** ${{ env.TARGET }} | |
| **Bootloader:** ${{ env.BOOTLOADER }} | |
| **Artifact Source:** ${{ inputs.use_latest_release && 'Latest Release' || 'Latest Workflow Run' }} | |
| ## Created Images | |
| $(find output/images/ -name "*.img" -o -name "*.img.bmap" | xargs ls -lh 2>/dev/null | awk '{print "- " $9 " (" $5 ")"}' || echo "- No images found") | |
| ## Download | |
| The SD card image is available as a workflow artifact above. | |
| EOF | |
| fi |