Build LinuxBox-Dev Images #303
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 LinuxBox-Dev Images | |
| # | |
| # Generates beta, stable or RC images for LinuxBox devices. You can select build runners. By default it generates all images, but you can build images only for one target | |
| # Images are placed at www.arnmbian.com and nighly beta also at https://github.com/armbian/build/releases/tag/latest | |
| # | |
| on: | |
| workflow_run: | |
| workflows: ["Build train"] | |
| types: | |
| - completed | |
| workflow_dispatch: | |
| inputs: | |
| choice: | |
| type: choice | |
| description: Build targets | |
| options: | |
| - beta | |
| - stable | |
| - rc | |
| runner: | |
| type: choice | |
| description: Build runners for CLI | |
| options: | |
| - small | |
| - ubuntu-latest | |
| sourcerepo: | |
| description: Source repository | |
| required: false | |
| default: 'nightly' | |
| packagesrepo: | |
| type: choice | |
| description: Beta packages repository | |
| options: | |
| - "yes" | |
| - "no" | |
| board: | |
| description: "Board: trhubv3, trhubv3b, linuxbox" | |
| required: false | |
| default: "trhubv3" | |
| dist: | |
| description: "Distribution: cn, us, kr" | |
| required: false | |
| default: "us" | |
| revision: | |
| description: "Revision (optional)" | |
| required: false | |
| default: "v1.13.01.12" | |
| advanced: | |
| description: 'Single board (grep -w tinkerboard |)' | |
| required: false | |
| default: '' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| jobs: | |
| Cancel: | |
| if: ${{ github.repository_owner == 'Armbian' && github.event.schedule == '' }} | |
| name: "Cancel currently active" | |
| runs-on: small | |
| steps: | |
| - name: Cancel Previous Runs | |
| uses: styfle/[email protected] | |
| with: | |
| access_token: ${{ secrets.GITHUB_TOKEN }} | |
| clean: | |
| if: ${{ github.repository_owner == 'Armbian' }} | |
| name: Purge older releases | |
| needs: [ Cancel ] | |
| runs-on: [ubuntu-latest] | |
| steps: | |
| - name: Purge | |
| uses: dev-drprasad/[email protected] | |
| with: | |
| keep_latest: 7 | |
| delete_tag_pattern: trunk | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - uses: igorjs/gh-actions-clean-workflow@v3 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| days_old: 14 | |
| fake: | |
| if: ${{ github.repository_owner == 'Armbian' }} | |
| runs-on: small | |
| needs: [ clean ] | |
| name: Source changes | |
| outputs: | |
| changes: ${{steps.list_releases.outputs.changes}} | |
| version: ${{steps.list_releases.outputs.version}} | |
| steps: | |
| - run: | | |
| echo "not empty" > changes | |
| - uses: actions/checkout@v3 | |
| if: ${{ github.repository_owner == 'Armbian' && github.event.inputs.choice != 'stable' && github.event.inputs.choice != 'rc' }} | |
| with: | |
| fetch-depth: 1 | |
| path: build | |
| clean: false | |
| ref: nightly | |
| - name: "Get latest release version" | |
| if: ${{ github.repository_owner == 'Armbian' && github.event.inputs.choice != 'stable' && github.event.inputs.choice != 'rc' }} | |
| id: list_releases | |
| run: | | |
| RELE=$(curl -ks https://api.github.com/repos/armbian/build/releases/latest ^| grep "browser_download_url" | grep -o -P '(?<=Armbian.).*(?=_)' | cut -d"_" -f1 | sort | uniq | head -1) | |
| SOUR=$(cat build/VERSION) | |
| # skip if version in git is the same as at release | |
| if [[ "$RELE" == "$SOUR" ]]; then | |
| echo ::set-output name=changes::$(echo 'true') | |
| fi | |
| # output version | |
| echo ::set-output name=version::$(echo ${SOUR}) | |
| - uses: actions/upload-artifact@v3 | |
| with: | |
| path: changes | |
| name: changes | |
| if-no-files-found: ignore | |
| - uses: actions/upload-artifact@v3 | |
| with: | |
| path: changes | |
| name: changes | |
| if-no-files-found: ignore | |
| generaterelease: | |
| needs: [ fake ] | |
| if: ${{ github.repository_owner == 'Armbian' && needs.fake.outputs.changes != 'true' }} | |
| runs-on: ubuntu-latest | |
| name: "Update latest release" | |
| steps: | |
| - run: | | |
| echo "Env: ${{ github.event.inputs.choice }}" | |
| echo "Env: ${{ github.event.inputs.runner }}" | |
| echo "Env: ${{ github.event.inputs.sourcerepo }}" | |
| echo "Branch: ${{ github.event.inputs.branch }}" | |
| echo "Version: ${{ needs.fake.outputs.version }}" | |
| - uses: actions/checkout@v3 | |
| if: ${{ github.repository_owner == 'Armbian' && github.event.inputs.choice != 'stable' && github.event.inputs.choice != 'rc' }} | |
| with: | |
| fetch-depth: 1 | |
| - uses: dev-drprasad/[email protected] | |
| if: ${{ github.repository_owner == 'Armbian' && github.event.inputs.choice != 'stable' && github.event.inputs.choice != 'rc' }} | |
| with: | |
| delete_release: true | |
| tag_name: latest | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - uses: ncipollo/release-action@v1 | |
| if: ${{ github.repository_owner == 'Armbian' && github.event.inputs.choice != 'stable' && github.event.inputs.choice != 'rc' }} | |
| with: | |
| artifacts: "LICENSE" | |
| tag: "${{ needs.fake.outputs.version }}" | |
| name: "Build in progress" | |
| bodyFile: ".github/Releases-wip.md" | |
| allowUpdates: true | |
| removeArtifacts: true | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| merge: | |
| needs: [ generaterelease ] | |
| uses: armbian/scripts/.github/workflows/merge-from-branch.yml@master | |
| with: | |
| branch: 'nightly' | |
| runner: small | |
| secrets: | |
| GPG_KEY2: ${{ secrets.GPG_KEY2 }} | |
| GPG_PASSPHRASE2: ${{ secrets.GPG_PASSPHRASE2 }} | |
| x86: | |
| needs: [ merge ] | |
| uses: armbian/scripts/.github/workflows/build-with-docker.yml@master | |
| with: | |
| variant: 'cli:${{ github.event.inputs.choice }}' | |
| sourcerepo: '${{ github.event.inputs.sourcerepo }}' | |
| packagesrepo: '${{ github.event.inputs.packagesrepo }}' | |
| runner: ubuntu-latest | |
| part: 1 | |
| of: 1 | |
| include: 'grep uefi-x86 | ${{ github.event.inputs.advanced }}' | |
| exclude: '' | |
| uploading: false | |
| secrets: | |
| GPG_KEY1: ${{ secrets.GPG_KEY1 }} | |
| GPG_PASSPHRASE1: ${{ secrets.GPG_PASSPHRASE1 }} | |
| GPG_KEY2: ${{ secrets.GPG_KEY2 }} | |
| GPG_PASSPHRASE2: ${{ secrets.GPG_PASSPHRASE2 }} | |
| SCRIPTS_ACCESS_TOKEN: ${{ secrets.SCRIPTS_ACCESS_TOKEN }} | |
| SSH_KEY_TORRENTS: ${{ secrets.KEY_TORRENTS }} | |
| KNOWN_HOSTS_UPLOAD: ${{ secrets.KNOWN_HOSTS_UPLOAD }} | |
| x86-desktop: | |
| needs: [ merge ] | |
| uses: armbian/scripts/.github/workflows/build-with-docker.yml@master | |
| with: | |
| variant: 'desktop:${{ github.event.inputs.choice }}' | |
| sourcerepo: '${{ github.event.inputs.sourcerepo }}' | |
| packagesrepo: '${{ github.event.inputs.packagesrepo }}' | |
| runner: "big" | |
| part: 1 | |
| of: 1 | |
| include: 'grep uefi-x86 | ${{ github.event.inputs.advanced }}' | |
| exclude: '' | |
| uploading: false | |
| secrets: | |
| GPG_KEY1: ${{ secrets.GPG_KEY1 }} | |
| GPG_PASSPHRASE1: ${{ secrets.GPG_PASSPHRASE1 }} | |
| GPG_KEY2: ${{ secrets.GPG_KEY2 }} | |
| GPG_PASSPHRASE2: ${{ secrets.GPG_PASSPHRASE2 }} | |
| SCRIPTS_ACCESS_TOKEN: ${{ secrets.SCRIPTS_ACCESS_TOKEN }} | |
| SSH_KEY_TORRENTS: ${{ secrets.KEY_TORRENTS }} | |
| KNOWN_HOSTS_UPLOAD: ${{ secrets.KNOWN_HOSTS_UPLOAD }} | |
| cli1: | |
| needs: [ merge ] | |
| uses: armbian/scripts/.github/workflows/build-with-docker.yml@master | |
| with: | |
| variant: 'cli:${{ github.event.inputs.choice }}' | |
| sourcerepo: '${{ github.event.inputs.sourcerepo }}' | |
| packagesrepo: '${{ github.event.inputs.packagesrepo }}' | |
| runner: ubuntu-latest | |
| part: 1 | |
| of: 2 | |
| include: '${{ github.event.inputs.advanced }}' | |
| exclude: 'grep -v uefi-x86 | ' | |
| uploading: false | |
| secrets: | |
| GPG_KEY1: ${{ secrets.GPG_KEY1 }} | |
| GPG_PASSPHRASE1: ${{ secrets.GPG_PASSPHRASE1 }} | |
| GPG_KEY2: ${{ secrets.GPG_KEY2 }} | |
| GPG_PASSPHRASE2: ${{ secrets.GPG_PASSPHRASE2 }} | |
| SCRIPTS_ACCESS_TOKEN: ${{ secrets.SCRIPTS_ACCESS_TOKEN }} | |
| SSH_KEY_TORRENTS: ${{ secrets.KEY_TORRENTS }} | |
| KNOWN_HOSTS_UPLOAD: ${{ secrets.KNOWN_HOSTS_UPLOAD }} | |
| cli2: | |
| needs: [ merge ] | |
| uses: armbian/scripts/.github/workflows/build-with-docker.yml@master | |
| with: | |
| variant: 'cli:${{ github.event.inputs.choice }}' | |
| sourcerepo: '${{ github.event.inputs.sourcerepo }}' | |
| packagesrepo: '${{ github.event.inputs.packagesrepo }}' | |
| runner: '${{ github.event.inputs.runner }}' | |
| part: 2 | |
| of: 2 | |
| include: '${{ github.event.inputs.advanced }}' | |
| exclude: 'grep -v uefi-x86 | ' | |
| uploading: false | |
| secrets: | |
| GPG_KEY1: ${{ secrets.GPG_KEY1 }} | |
| GPG_PASSPHRASE1: ${{ secrets.GPG_PASSPHRASE1 }} | |
| GPG_KEY2: ${{ secrets.GPG_KEY2 }} | |
| GPG_PASSPHRASE2: ${{ secrets.GPG_PASSPHRASE2 }} | |
| SCRIPTS_ACCESS_TOKEN: ${{ secrets.SCRIPTS_ACCESS_TOKEN }} | |
| SSH_KEY_TORRENTS: ${{ secrets.KEY_TORRENTS }} | |
| KNOWN_HOSTS_UPLOAD: ${{ secrets.KNOWN_HOSTS_UPLOAD }} | |
| desktop1: | |
| needs: [ merge ] | |
| uses: armbian/scripts/.github/workflows/build-with-docker.yml@master | |
| with: | |
| variant: 'desktop:${{ github.event.inputs.choice }}' | |
| sourcerepo: '${{ github.event.inputs.sourcerepo }}' | |
| packagesrepo: '${{ github.event.inputs.packagesrepo }}' | |
| runner: "big" | |
| part: 1 | |
| of: 2 | |
| include: '${{ github.event.inputs.advanced }}' | |
| exclude: 'grep -v uefi-x86 | ' | |
| uploading: false | |
| secrets: | |
| GPG_KEY1: ${{ secrets.GPG_KEY1 }} | |
| GPG_PASSPHRASE1: ${{ secrets.GPG_PASSPHRASE1 }} | |
| GPG_KEY2: ${{ secrets.GPG_KEY2 }} | |
| GPG_PASSPHRASE2: ${{ secrets.GPG_PASSPHRASE2 }} | |
| SCRIPTS_ACCESS_TOKEN: ${{ secrets.SCRIPTS_ACCESS_TOKEN }} | |
| SSH_KEY_TORRENTS: ${{ secrets.KEY_TORRENTS }} | |
| KNOWN_HOSTS_UPLOAD: ${{ secrets.KNOWN_HOSTS_UPLOAD }} | |
| desktop2: | |
| needs: [ merge ] | |
| uses: armbian/scripts/.github/workflows/build-with-docker.yml@master | |
| with: | |
| variant: 'desktop:${{ github.event.inputs.choice }}' | |
| sourcerepo: '${{ github.event.inputs.sourcerepo }}' | |
| packagesrepo: '${{ github.event.inputs.packagesrepo }}' | |
| runner: "big" | |
| part: 2 | |
| of: 2 | |
| include: '${{ github.event.inputs.advanced }}' | |
| exclude: 'grep -v uefi-x86 | ' | |
| uploading: false | |
| secrets: | |
| GPG_KEY1: ${{ secrets.GPG_KEY1 }} | |
| GPG_PASSPHRASE1: ${{ secrets.GPG_PASSPHRASE1 }} | |
| GPG_KEY2: ${{ secrets.GPG_KEY2 }} | |
| GPG_PASSPHRASE2: ${{ secrets.GPG_PASSPHRASE2 }} | |
| SCRIPTS_ACCESS_TOKEN: ${{ secrets.SCRIPTS_ACCESS_TOKEN }} | |
| SSH_KEY_TORRENTS: ${{ secrets.KEY_TORRENTS }} | |
| KNOWN_HOSTS_UPLOAD: ${{ secrets.KNOWN_HOSTS_UPLOAD }} | |
| linuxbox-build: | |
| name: Build LinuxBox firmware | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: hubv3 | |
| - name: Free up disk space | |
| run: | | |
| echo "=== Initial disk usage ===" | |
| df -h | |
| echo "" | |
| echo "=== Removing unnecessary software ===" | |
| # Remove Android SDK | |
| sudo rm -rf /usr/local/lib/android || true | |
| # Remove .NET | |
| sudo rm -rf /usr/share/dotnet || true | |
| # Remove Haskell | |
| sudo rm -rf /opt/ghc || true | |
| sudo rm -rf /usr/local/.ghcup || true | |
| # Remove CodeQL | |
| sudo rm -rf /opt/hostedtoolcache/CodeQL || true | |
| # Remove large tool caches | |
| sudo rm -rf /opt/hostedtoolcache/* || true | |
| # Remove large packages | |
| sudo apt-get remove -y '^aspnetcore-.*' '^dotnet-.*' '^llvm-.*' 'php.*' '^mongodb-.*' '^mysql-.*' azure-cli google-chrome-stable firefox powershell mono-devel libgl1-mesa-dri || true | |
| # Remove Docker images and containers | |
| docker rmi $(docker image ls -aq) >/dev/null 2>&1 || true | |
| docker system prune -a -f || true | |
| # Remove swap | |
| sudo swapoff -a || true | |
| sudo rm -f /mnt/swapfile || true | |
| sudo rm -f /swapfile || true | |
| echo "" | |
| echo "=== Disk usage after cleanup ===" | |
| df -h | |
| echo "" | |
| echo "=== Cleaning up previous build artifacts ===" | |
| sudo rm -rf /mnt/linuxbox /mnt/output | |
| echo "=== Final disk usage ===" | |
| df -h | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| # Install essential build tools for U-boot and kernel compilation | |
| sudo apt-get install -y uuid-runtime systemd acl sudo git dialog psmisc uuid curl gawk ca-certificates \ | |
| gcc build-essential python3 python3-dev python3-venv python3-pip pv xz-utils patchutils \ | |
| binfmt-support qemu-user-static \ | |
| bc bison flex libssl-dev libncurses5-dev libncursesw5-dev \ | |
| device-tree-compiler u-boot-tools swig libpython3-dev \ | |
| gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu \ | |
| ccache ntpdate imagemagick pixz | |
| sudo apt-get autoremove -y || true | |
| sudo apt-get clean || true | |
| # Clean apt cache | |
| sudo rm -rf /var/lib/apt/lists/* || true | |
| sudo rm -rf /var/cache/apt/archives/* || true | |
| - name: Setup QEMU for ARM emulation | |
| run: | | |
| echo "Setting up QEMU for ARM emulation..." | |
| sudo systemctl restart systemd-binfmt.service || true | |
| docker run --rm --privileged multiarch/qemu-user-static --reset -p yes || true | |
| echo "Verifying QEMU registration..." | |
| ls -la /proc/sys/fs/binfmt_misc/ || true | |
| cat /proc/sys/fs/binfmt_misc/qemu-aarch64 || echo "qemu-aarch64 not registered" | |
| - name: Setup output directory symlink | |
| run: | | |
| echo "Setting up output directory symlink..." | |
| sudo mkdir -p /mnt/output | |
| sudo chown -R $USER:$USER /mnt/output | |
| ln -s /mnt/output ${{ github.workspace }}/output | |
| echo "Symlink created: ${{ github.workspace }}/output -> /mnt/output" | |
| ls -lah ${{ github.workspace }}/ | |
| - name: Make script executable | |
| run: chmod +x make_armbian_for_hubv3.sh | |
| - name: Clean build cache | |
| run: | | |
| echo "Cleaning potentially corrupted build cache..." | |
| # Remove any existing U-boot build artifacts that might cause issues | |
| sudo rm -rf cache/sources/u-boot/*/build 2>/dev/null || true | |
| sudo rm -rf cache/sources/u-boot/*/.config 2>/dev/null || true | |
| sudo rm -rf cache/sources/u-boot/*/include/config 2>/dev/null || true | |
| sudo rm -rf cache/sources/u-boot/*/include/generated 2>/dev/null || true | |
| sudo rm -rf cache/sources/linux-*/build 2>/dev/null || true | |
| # Ensure proper ownership of cache directory | |
| sudo chown -R $USER:$USER cache/ 2>/dev/null || true | |
| echo "Build cache cleaned" | |
| - name: Build firmware | |
| env: | |
| NO_APT_CACHER: yes | |
| run: | | |
| if [ -n "${{ github.event.inputs.revision }}" ]; then | |
| ./make_armbian_for_hubv3.sh -b ${{ github.event.inputs.board }} -d ${{ github.event.inputs.dist }} -r ${{ github.event.inputs.revision }} | |
| else | |
| ./make_armbian_for_hubv3.sh -b ${{ github.event.inputs.board }} -d ${{ github.event.inputs.dist }} | |
| fi | |
| - name: List output files for debugging | |
| run: | | |
| echo "Checking output directory structure..." | |
| ls -lah output/ || echo "output/ not found" | |
| ls -lah output/images/ || echo "output/images/ not found" | |
| find output -name "*.img" -type f 2>/dev/null || echo "No .img files found in output/" | |
| echo "Disk usage after build:" | |
| df -h | |
| - name: Upload images as artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: LinuxBox-images${{ github.event.inputs.revision && format('-{0}', github.event.inputs.revision) || '' }} | |
| path: | | |
| output/images/*.img | |
| output/images/*.xz | |
| if-no-files-found: warn | |
| - name: Clean up after upload | |
| run: | | |
| echo "Cleaning up after successful upload..." | |
| sudo rm -rf /mnt/output /mnt/linuxbox | |
| echo "Final disk usage:" | |
| df -h | |
| jobsend: | |
| name: finish | |
| needs: [x86,x86-desktop,cli1,desktop1,cli2,desktop2,linuxbox-build] | |
| runs-on: [ubuntu-latest] | |
| if: ${{ github.repository_owner == 'Armbian' && github.event.inputs.choice != 'stable' && github.event.inputs.choice != 'rc' }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v3 | |
| with: | |
| fetch-depth: 1 | |
| ref: nightly | |
| - name: Make build list | |
| run: | | |
| sudo npm install --location=global json || true | |
| truncate README.me --size=0 || true | |
| echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV | |
| cat ".github/Releases.md" >> README.tmp | |
| echo -en " \n\n" >> README.tmp | |
| echo "| Image | GPG | SHA | Release | Branch | Variant | Size | Kernel |" >> README.tmp | |
| echo "| --- | :--: | :--: | :--: | :--: | :--: | --: | --: |" >> README.tmp | |
| gh release view --json assets 2>/dev/null | python3 -mjson.tool | sed '1,2d;$d' | json -ga name url size -d, | sort | ( | |
| while read -r line; do | |
| name=$(echo $line | cut -d"," -f1 | awk '{print tolower($0)}') | |
| url=$(echo $line | cut -d"," -f2) | |
| size=$(echo $line | cut -d"," -f3) | |
| if [ "${name: -3}" == ".xz" ]; then | |
| board_name=$(echo $name | cut -d"_" -f3) | |
| source config/boards/$board_name.* | |
| out_release=$(echo $name | cut -d"_" -f4) | |
| out_branch=$(echo $name | cut -d"_" -f5) | |
| out_kernel=$(echo $name | cut -d"_" -f6-7 | cut -d"." -f1-3 | cut -d"_" -f1) | |
| out_desktop=$(echo $name | cut -d"_" -f7) | |
| out_desktop=${out_desktop:-cli} | |
| out_size=$(echo "scale=2; $size/1024/1024" | bc -l)" Mb" | |
| echo -ne "| [$BOARD_NAME]($url) | [:file_folder:]($url".asc") | [:file_folder:]($url".sha") | $out_release | $out_branch | $out_desktop | $out_size | $out_kernel |\n" >> README.tmp | |
| fi | |
| done | |
| ) | |
| cat README.tmp | |
| - uses: ncipollo/release-action@v1 | |
| with: | |
| tag: "${{ env.VERSION }}" | |
| bodyFile: "README.tmp" | |
| name: "Armbian ${{ env.VERSION }}" | |
| allowUpdates: true | |
| token: ${{ secrets.GITHUB_TOKEN }} |