Skip to content

OpenWrt Matrix · BPI-R4-SD · 24.10 #9

OpenWrt Matrix · BPI-R4-SD · 24.10

OpenWrt Matrix · BPI-R4-SD · 24.10 #9

# Reusable workflow for building OpenWrt firmware
name: OpenWrt-Matrix
run-name: OpenWrt Matrix · ${{ inputs.targets || 'all-targets' }} · ${{ github.ref_name }}
on:
workflow_call:
inputs:
targets:
required: true
type: string
default: ""
upload_source:
required: false
type: boolean
default: false
build_firmware:
required: false
type: boolean
default: true
workflow_dispatch:
inputs:
targets:
description: "Select targets (comma separated, e.g. BPI-R4-EMMC,BPI-R4-SD,BPI-R4-SNAND,BPI-R4-PRO; leave blank for all, case-insensitive)"
required: false
type: string
default: ""
upload_source:
description: "Upload source folder before build"
required: false
type: boolean
default: false
build_firmware:
description: "Build and publish firmware"
required: false
type: boolean
default: true
permissions:
contents: write
concurrency:
group: openwrt-matrix-${{ github.ref }}-${{ inputs.targets || 'all' }}
cancel-in-progress: false
jobs:
setup:
runs-on: ubuntu-24.04
if: github.event.repository.owner.id == github.event.sender.id
steps:
- id: set-matrix
shell: bash
run: |
# All possible targets
all_targets='[
{"name": "BPI-R4-EMMC", "script_dir": "BPI-R4", "seed": "BPI-R4", "arch": "mediatek/filogic", "arch_suffix": "mt7988", "bundle_kind": "emmc", "base_name": "BPI-R4", "gpt_layout": "bpi-r4-emmc-8g-ab.json"},
{"name": "BPI-R4-SD", "script_dir": "BPI-R4", "seed": "BPI-R4", "arch": "mediatek/filogic", "arch_suffix": "mt7988", "bundle_kind": "sd", "base_name": "BPI-R4", "gpt_layout": "bpi-r4-sd-ab.json"},
{"name": "BPI-R4-SNAND", "script_dir": "BPI-R4", "seed": "BPI-R4-NAND", "arch": "mediatek/filogic", "arch_suffix": "mt7988", "bundle_kind": "snand", "base_name": "BPI-R4", "gpt_layout": ""},
{"name": "BPI-R4-PRO", "script_dir": "BPI-R4-PRO", "seed": "BPI-R4-PRO", "arch": "mediatek/filogic", "arch_suffix": "mt7988", "bundle_kind": "generic", "base_name": "BPI-R4-PRO", "gpt_layout": ""}
]'
# User selected targets
inputs_targets="${{ inputs.targets }}"
# Replace Chinese comma with English comma, convert to uppercase
inputs_targets=$(echo "$inputs_targets" | sed 's/,/,/g' | tr 'a-z' 'A-Z' | xargs)
if [[ -z "$inputs_targets" ]]; then
# If input is empty, run all targets
echo "matrix=$(echo "$all_targets" | jq -c '{include: .}')" >> $GITHUB_OUTPUT
else
# Filter targets based on input
filtered_targets=$(echo "$all_targets" | jq --arg targets "$inputs_targets" '[.[] | select(.name as $name | ($targets | split(",") | map(gsub(" "; "")) | index($name))) ]')
echo "matrix=$(echo "$filtered_targets" | jq -c '{include: .}')" >> $GITHUB_OUTPUT
fi
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
build:
needs: setup
env: # default values, will be overridden later
seed: dummy
artifact_prefix: dummy
sha_match: dummy
ext4_zip: dummy
sfs_zip: dummy
sysupgrade_glob: dummy
openwrt_source_name: dummy
TARGET_DEVICE_ARCH: dummy
latest_release: dummy
bundle_kind: dummy
base_name: dummy
gpt_layout: dummy
runs-on: ubuntu-24.04
if: github.event.repository.owner.id == github.event.sender.id
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup.outputs.matrix) }}
steps:
- name: Generate platform variables and print
id: genvars
run: |
# Debug: Print all input variables
echo "inputs.targets: '${{ inputs.targets }}'"
echo "inputs.upload_source: '${{ inputs.upload_source }}'"
echo "inputs.build_firmware: '${{ inputs.build_firmware }}'"
echo "matrix.name: '${{ matrix.name }}'"
echo "matrix.script_dir: '${{ matrix.script_dir }}'"
echo "matrix.seed: '${{ matrix.seed }}'"
echo "matrix.arch: '${{ matrix.arch }}'"
echo "matrix.arch_suffix: '${{ matrix.arch_suffix }}'"
echo "matrix.bundle_kind: '${{ matrix.bundle_kind }}'"
echo "matrix.base_name: '${{ matrix.base_name }}'"
echo "matrix.gpt_layout: '${{ matrix.gpt_layout }}'"
echo "github.run_id: '${{ github.run_id }}'"
# Platform name in lowercase
name_lower=$(echo "${{ matrix.name }}" | tr 'A-Z' 'a-z')
# seed rule
seed="${{ matrix.seed }}"
# artifact_prefix rule
artifact_prefix="YAOF-${{ matrix.name }}"
bundle_kind="${{ matrix.bundle_kind }}"
base_name="${{ matrix.base_name }}"
gpt_layout="${{ matrix.gpt_layout }}"
# sha_match rule
sha_match="$name_lower"
# ext4_zip/sfs_zip rule
if [ "$name_lower" = "x86" ]; then
ext4_zip='*ext4-combined*'
sfs_zip='*squashfs-combined*'
sysupgrade_glob='*combined-efi.img*'
elif [ "$name_lower" = "bpi-r4" ]; then
ext4_zip='*bpi-r4*ext4*'
sfs_zip='*bpi-r4*squashfs*'
sysupgrade_glob='*bpi-r4*'
else
ext4_zip="*$name_lower*ext4*"
sfs_zip="*$name_lower*squashfs*"
sysupgrade_glob='*sysupgrade.img*'
fi
# workerid variable
workerid=${{ github.run_id }}
# openwrt_source_name archive name
openwrt_source_name="openwrt-source-${{ matrix.name }}-${workerid}.tar"
cat <<EOF | tee -a $GITHUB_ENV
seed=$seed
artifact_prefix=$artifact_prefix
sha_match=$sha_match
ext4_zip=$ext4_zip
sfs_zip=$sfs_zip
sysupgrade_glob=$sysupgrade_glob
openwrt_source_name=$openwrt_source_name
bundle_kind=$bundle_kind
base_name=$base_name
gpt_layout=$gpt_layout
EOF
- name: Show system info
run: |
echo -e "Total CPU cores\t: $(nproc)"
cat /proc/cpuinfo | grep 'model name'
- name: Maximize build space
if: inputs.build_firmware
uses: easimon/maximize-build-space@master
with:
swap-size-mb: 2048
temp-reserve-mb: 128
root-reserve-mb: 1024
remove-dotnet: "true"
remove-android: "true"
remove-haskell: "true"
remove-codeql: "true"
- name: Checkout
uses: actions/checkout@v4
- name: Init build dependencies
env:
DEBIAN_FRONTEND: noninteractive
run: |
sudo rm -rf /var/lib/apt/lists/* || true
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache/CodeQL || true
sudo -E apt-get -o Acquire::Languages=none -qq update
sudo -E apt-get -y -qq --no-install-recommends install asciidoc bash bin86 binutils bison bzip2 clang file flex g++ g++-multilib gawk gcc-multilib gettext git gzip help2man intltool libbpf-dev libelf-dev libncurses-dev libssl-dev libthread-queue-any-perl libusb-dev libxml-parser-perl make patch perl-modules pkg-config python3-dev python3-pip python3-pyelftools python3-setuptools rsync sharutils swig time unzip util-linux wget xsltproc zlib1g-dev zip zstd
sudo -E apt-get -y -qq --no-install-recommends install dos2unix dwarves jq npm quilt xz-utils
sudo -E npm install -g pnpm
pip3 install --user -U pylibfdt --break-system-packages
sudo -E apt-get -qq autoremove --purge
sudo -E apt-get -qq clean
sudo -E git config --global user.name 'GitHub Actions' && git config --global user.email 'noreply@github.com'
sudo -E git config --global core.abbrev auto
df -h
- name: Prepare Mixedwrt
run: |
sudo chown -R runner:runner "$(dirname "$GITHUB_WORKSPACE")"
cp -r ./SCRIPTS/${{ matrix.script_dir }}/. ./SCRIPTS/
cp -r ./SCRIPTS/. ./
/bin/bash 01_get_ready.sh
- name: Prepare Package
working-directory: ${{ github.workspace }}/openwrt
run: |
cp -r ../SCRIPTS/. ./
/bin/bash 02_prepare_package.sh
/bin/bash 02_target_only.sh
/bin/bash 04_remove_upx.sh
- name: QTMDFW4
working-directory: ${{ github.workspace }}/openwrt
run: |
cp -rf ../SEED/${{ env.seed }}/config.seed .config
- name: Convert Translation
working-directory: ${{ github.workspace }}/openwrt
run: |
/bin/bash 03_convert_translation.sh
- name: Add ACL
working-directory: ${{ github.workspace }}/openwrt
run: |
/bin/bash 05_create_acl_for_luci.sh -a
- name: Fix Permissions
working-directory: ${{ github.workspace }}/openwrt
run: |
sudo -E chmod -R 755 ./08_fix_permissions.sh
/bin/bash 08_fix_permissions.sh
- name: Make Config
working-directory: ${{ github.workspace }}/openwrt
run: |
make defconfig
- name: Get Architecture
id: getarch
working-directory: ${{ github.workspace }}/openwrt
run: |
TARGET_DEVICE_ARCH="$(grep "^CONFIG_TARGET_.*_.*=y$" ".config" | head -n 1 | sed 's/^CONFIG_TARGET_//g' | awk -F '_' '{print $1}')"
if [ -n "${{ matrix.arch_suffix }}" ]; then
TARGET_DEVICE_ARCH="$TARGET_DEVICE_ARCH-${{ matrix.arch_suffix }}"
fi
echo "TARGET_DEVICE_ARCH=$TARGET_DEVICE_ARCH" >> $GITHUB_ENV
latest_release="$(curl -s https://github.com/openwrt/openwrt/tags | grep -Eo "v[0-9\.]+\-*r*c*[0-9]*.tar.gz" | grep 'v24.10' | sed -n 1p | sed 's/.tar.gz//g' | sed 's/v//g')"
echo "latest_release=${latest_release}" >> $GITHUB_ENV
echo "Package folder ${{ env.openwrt_source_name }}"
cd ..
# Must use tar, otherwise symbolic links will be incomplete
if [ "${{ inputs.upload_source }}" = "true" ]; then
tar -cf ${{ env.openwrt_source_name }} openwrt
fi
# upload_source
- name: Upload Source Archive
if: inputs.upload_source
uses: actions/upload-artifact@v4
with:
name: ${{ env.openwrt_source_name }}
path: |
${{ env.openwrt_source_name }}
retention-days: 5
- name: Make Download
if: inputs.build_firmware
working-directory: ${{ github.workspace }}/openwrt
run: |
if [ "${{ inputs.upload_source }}" = "true" ] && [ -f ../${{ env.openwrt_source_name }} ]; then
rm ../${{ env.openwrt_source_name }}
fi
make download -j50
make -j$(($(nproc) + 1)) package/network/utils/nftables/refresh V=s
# build_firmware
- name: Compile Openwrt
if: inputs.build_firmware
working-directory: ${{ github.workspace }}/openwrt
id: compileopenwrt
continue-on-error: true
run: |
IGNORE_ERRORS=1 make -j$(($(nproc) + 1))
echo $?
- name: If Error
if: steps.compileopenwrt.outcome == 'failure'
working-directory: ${{ github.workspace }}/openwrt
run: |
cat ./.config
echo '================================================================'
make -j1 V=s
- name: Organize files
if: inputs.build_firmware
id: organize
env:
LATEST_RELEASE: ${{ env.latest_release }}
run: |
rm -rf ./artifact/
mkdir -p ./artifact/
cp -a openwrt/bin/targets/${{ matrix.arch }}/. ./artifact/ || true
cd ./artifact/
ls -Ahl
gzip -d *.gz || true
gzip --best *.img || true
BUILD_DATE=$(date +%Y-%m-%d)
if [ "${{ env.base_name }}" = "BPI-R4" ]; then
shopt -s nullglob
COMMON_FILES=(
openwrt-mediatek-filogic-bananapi_bpi-r4-squashfs-sysupgrade.itb
openwrt-mediatek-filogic-bananapi_bpi-r4.manifest
)
if [ "${{ env.bundle_kind }}" = "sd" ]; then
BUNDLE_FILES=(
openwrt-mediatek-filogic-bananapi_bpi-r4-sdcard.img.gz
"${COMMON_FILES[@]}"
)
elif [ "${{ env.bundle_kind }}" = "emmc" ]; then
BUNDLE_FILES=(
openwrt-mediatek-filogic-bananapi_bpi-r4-emmc-preloader.bin
openwrt-mediatek-filogic-bananapi_bpi-r4-emmc-bl31-uboot.fip
"${COMMON_FILES[@]}"
)
elif [ "${{ env.bundle_kind }}" = "snand" ]; then
BUNDLE_FILES=(
openwrt-mediatek-filogic-bananapi_bpi-r4-snand-preloader.bin
openwrt-mediatek-filogic-bananapi_bpi-r4-snand-bl31-uboot.fip
"${COMMON_FILES[@]}"
)
else
BUNDLE_FILES=(openwrt-mediatek-filogic-bananapi_bpi-r4*)
fi
sha256sum openwrt-mediatek-filogic-bananapi_bpi-r4* \
| tee YAOF-${{ matrix.name }}-${BUILD_DATE}-${{ env.latest_release }}.sha256sum
zip YAOF-${{ matrix.name }}-${BUILD_DATE}-${{ env.latest_release }}.zip "${BUNDLE_FILES[@]}"
else
sha256sum openwrt*${{ env.sha_match }}* | tee ${{ env.artifact_prefix }}-${BUILD_DATE}-${{ env.latest_release }}.sha256sum
zip ${{ env.artifact_prefix }}-${BUILD_DATE}-${{ env.latest_release }}-ext4.zip ${{ env.ext4_zip }}
zip ${{ env.artifact_prefix }}-${BUILD_DATE}-${{ env.latest_release }}-sfs.zip ${{ env.sfs_zip }}
fi
ls -Ahl
- name: Validate BPI-R4 release artifacts
if: inputs.build_firmware && matrix.base_name == 'BPI-R4'
run: |
python3 -m unittest \
tests/test_validate_bpi_r4_bundles.py \
tests/test_validate_bpi_r4_layouts.py
bundle_path=$(find ./artifact -maxdepth 1 -name "YAOF-${{ matrix.name }}-*.zip" | head -n 1)
test -n "$bundle_path"
python3 tools/validate_bpi_r4_layouts.py --json > ./artifact/YAOF-BPI-R4-layout-validation-${{ env.latest_release }}.json
python3 tools/validate_bpi_r4_bundles.py "$bundle_path" --json > ./artifact/YAOF-BPI-R4-bundle-validation-${{ matrix.name }}-${{ env.latest_release }}.json
- name: Create release
if: inputs.build_firmware
id: create_release
uses: ncipollo/release-action@main
with:
name: YAOF for BPI-R4 ${{ env.latest_release }}
allowUpdates: true
prerelease: ${{ contains(env.latest_release, 'rc') }}
tag: ${{ env.latest_release }}
commit: ${{ github.sha }}
replacesArtifacts: true
token: ${{ secrets.GITHUB_TOKEN }}
generateReleaseNotes: true
artifacts: |
./artifact/*.zip
./artifact/*.sha256sum
./artifact/*.json
- name: Print Disk Space After
run: df -h
- name: Trigger badge sync for current platform
if: github.workflow == 'OpenWrt-Matrix' && inputs.build_firmware && steps.create_release.outcome != 'skipped' && always()
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "Triggering badge sync for ${{ matrix.name }} with status: ${{ steps.create_release.outcome }}"
gh workflow run "${{ matrix.name }}-OpenWrt.yml" \
--field badge_status="${{ steps.create_release.outcome }}" || echo "Failed to trigger ${{ matrix.name }} workflow"