Firmware PR #2166 added a `size-report` Makefile target + the `general/scripts/size_report.py` analyser that emits a per-package / per-kernel-module `sizes.<soc>-<variant>.json` next to the .tgz. Builder clones firmware fresh on every run and shells to `make BOARD=...`, so the script + target are already available downstream — this PR adds the CI wiring and manifest extension so the JSON ships as a release asset and surfaces through https://openipc.github.io/builder/manifest.json. Three changes: * `builder.sh`: best-effort `make size-report` after the main build, and copy `sizes.*.json` into the timestamped archive next to `.tgz` / `rootfs.squashfs.*`. Failure is swallowed so a legacy `OPENIPC_FW_REV` pin to a pre-#2166 firmware ref can't sink the build. * `.github/workflows/master.yml`: new `Build size report` step after the existing `Build firmware`. Mirrors the bimodal rename trick the .tgz path already does — compound matrix entries (`<soc>_<variant>_<vendor>-<model>`) share `<soc>_<variant>` and would otherwise collide on the firmware-side `sizes.<soc>-<variant>.json` filename when uploaded to the same release tag. Compound entries get the JSON renamed to `sizes.<NAME>.json`; simple entries keep `sizes.<soc>-<variant>.json`. `${{env.SIZES}}` is added to all three upload `files:` blocks (dated / nightly / latest). * `.github/scripts/enrich_manifest.py`: `SIZES_COMPOUND_RE` + `SIZES_SIMPLE_RE`, a `parse_sizes()` helper that tries compound first (because `[^._-]+` in the simple soc class would otherwise accept the compound form too), the sidecar is recorded at the platform level under a `"sizes"` key in `manifest.json`, and a new `@sizes <build_id> <platform> <size> <url>` line type is emitted in `manifest.flat` alongside the existing `@channel` directive. Schema is unchanged for existing consumers — on-device sysupgrade reads positional 4-column `manifest.flat` lines and stays inert on unknown `@`-prefixed directives. Co-authored-by: John <zekccsripfwrocp-15689@yn.furvionx.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
355 lines
13 KiB
YAML
355 lines
13 KiB
YAML
name: Build
|
|
on:
|
|
schedule:
|
|
- cron: '0 3 * * *'
|
|
workflow_dispatch:
|
|
inputs:
|
|
platform:
|
|
description: Platform
|
|
required: false
|
|
|
|
jobs:
|
|
preflight:
|
|
name: Preflight
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
should_build: ${{ steps.gate.outputs.should_build }}
|
|
head_sha: ${{ steps.gate.outputs.head_sha }}
|
|
short_sha: ${{ steps.gate.outputs.short_sha }}
|
|
build_id: ${{ steps.gate.outputs.build_id }}
|
|
built_at: ${{ steps.gate.outputs.built_at }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- id: gate
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
HEAD=$(git rev-parse HEAD)
|
|
SHORT=$(git rev-parse --short HEAD)
|
|
BUILD_ID="nightly-$(date -u +%Y%m%d)-${SHORT}"
|
|
BUILT_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
# Nightly rebuilds unconditionally on schedule. builder.sh re-clones
|
|
# OpenIPC/firmware at HEAD on every run, so the relevant inputs are
|
|
# mostly outside this repo (firmware HEAD, toolchain release, kernel
|
|
# tarball, vendor osdrv, individual package upstreams). The previous
|
|
# gate skipped when only this repo's HEAD matched the last published
|
|
# nightly, which made upstream fixes (e.g. an openhisilicon mipi_rx
|
|
# regression fix that lands in firmware) invisible to users until
|
|
# something here happened to change. Always build on schedule.
|
|
echo "Build: $BUILD_ID (event=${{ github.event_name }})"
|
|
echo "should_build=true" >> "$GITHUB_OUTPUT"
|
|
echo "head_sha=$HEAD" >> "$GITHUB_OUTPUT"
|
|
echo "short_sha=$SHORT" >> "$GITHUB_OUTPUT"
|
|
echo "build_id=$BUILD_ID" >> "$GITHUB_OUTPUT"
|
|
echo "built_at=$BUILT_AT" >> "$GITHUB_OUTPUT"
|
|
|
|
buildroot:
|
|
name: Firmware
|
|
needs: preflight
|
|
if: needs.preflight.outputs.should_build == 'true'
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
BUILD_ID: ${{ needs.preflight.outputs.build_id }}
|
|
BUILD_SHA: ${{ needs.preflight.outputs.head_sha }}
|
|
BUILD_PLATFORM: ${{ matrix.platform }}
|
|
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
platform:
|
|
- gk7202v300_lite_cootli_camv0103
|
|
- gk7202v300_lite_ipg-g3-wr
|
|
- gk7202v300_lite_xg521
|
|
- gk7205v200_lite_tiandy-tc-c321n
|
|
- gk7205v200_lite_vixand-ipc-1
|
|
- gk7205v200_lite_vixand-iph-5-4g
|
|
- gk7205v210_lite_tiandy-tc-c32qn
|
|
- gk7205v210_lite_vixand-ivg-g3s
|
|
- gk7205v210_lite_vixand-ivg-g4f-a
|
|
- gk7205v210_lite_vixand-ivg-g4f-a-w
|
|
- gk7205v210_lite_vixand-ivg-g4h
|
|
- gk7205v300_lite_vixand-ivg-g6s
|
|
- gk7205v300_lite_vixand-ivg-g6s-w
|
|
- hi3516cv200_lite_trassir-tr-d4121ir1-v2
|
|
- hi3516ev300_ultimate_rostelecom-ipc8232swc-we
|
|
- hi3516ev300_ultimate_rvi-1ncmw2028
|
|
- hi3518ev200_lite_smartwares-cip-37210
|
|
- hi3518ev200_lite_switcam-hs303
|
|
- hi3518ev200_lite_switcam-hs303-v2
|
|
- hi3518ev200_lite_vstarcam-c8892wip
|
|
- hi3518ev200_lite_qtech-qvc-ipc-136w
|
|
- hi3518ev300_lite_bathhouse
|
|
- hi3518ev300_lite_xiaomi-mjsxj02hl
|
|
- hi3518ev200_ultimate_lenovo-snowman-1080p
|
|
- ssc30kd_lite_cmcc-ds-ytj5301
|
|
- ssc325_lite_imilab-ec3-cmsxj25a
|
|
- ssc325_lite_imou-c22cp
|
|
- ssc325_lite_tp-link-tapo-c310-v1
|
|
- ssc325_lite_trassir-tr-w2c1-v1
|
|
- ssc325de_lite_imou-c22ep-s2
|
|
- ssc333_lite_meari-speed-6s
|
|
- ssc333_lite_tp-link-tapo-c110-v2
|
|
- ssc333_lite_tp-link-tapo-c110-v26
|
|
- ssc333_lite_babysense-see-hd-ip206
|
|
- ssc333_lite_vstarcam-c43s_b
|
|
- ssc335_lite_tp-link-tapo-c110-v1
|
|
- ssc335_lite_tp-link-tapo-c310-v220
|
|
- ssc335_lite_trassir-tr-w2c1-v2
|
|
- ssc335de_lite_dahua-hfw1230sp-v2
|
|
- ssc335de_lite_imou-c22e-s2-v2
|
|
- ssc335de_lite_uniview-c1l-2wn-g
|
|
- ssc337_lite_h3c-tc2101
|
|
- ssc337_lite_tiandy-tc-c321n-v2
|
|
- ssc337_lite_tp-link-tapo-c110-v1
|
|
- ssc337de_ultimate_foscam-x5
|
|
- ssc338q_fpv_caddx-fly
|
|
- ssc338q_fpv_emax-wyvern-link
|
|
- ssc338q_fpv_openipc-mario-aio
|
|
- ssc338q_fpv_openipc-thinker-aio
|
|
- ssc338q_fpv_openipc-urllc-aio
|
|
- ssc338q_fpv_runcam-wifilink
|
|
- ssc377qe_fpv_ccdcam-im50q01-tipoman
|
|
- t10_lite_hb-wifi-z6
|
|
- t10_lite_jvs-ingt10-gqs60ep
|
|
- t20_ultimate_azarton-c1
|
|
- t20_lite_ec37-t11
|
|
- t31_lite_vstarcam-cs55
|
|
- t21_lite_chinamobile-hdc-51-a5-v12
|
|
- t21_lite_smartwares-cip-37210at
|
|
- t21_lite_xyx-06s
|
|
- t21_lite_wansview-q5-1080p
|
|
- t23_lite_jooan-a6m-u
|
|
- t23_lite_jooan-q3r-u
|
|
- t23_lite_lsc-3215672
|
|
- t31_lite_aceline-aip-o4
|
|
- t31_lite_wansview-q5-2k
|
|
- t31_lite_aoni-ep01j05
|
|
- t31_lite_chinamobile-hdc-51-a6-v11
|
|
- t31_lite_cmcc-hdc-51-a6-v10
|
|
- t31_lite_chinatelecom-y4h-50
|
|
- t31_lite_wyze-v3b
|
|
- t31_lite_xiaomi-mjsxj03hl
|
|
- t31_lite_xiaomi-mjsxj03hl-jxq03
|
|
- t31_lite_tuya-gv7630-t31-ptz
|
|
- t31_ultimate_azarton-c1-t31x
|
|
- t31_ultimate_gcraftsman-gca50
|
|
- t31_lite_zte-k540
|
|
- t40_lite_movols-mo-805p
|
|
|
|
# APFPV
|
|
- ssc30kq_apfpv_greg-generic-bu-eu
|
|
- ssc30kq_apfpv_greg-generic-cu-eu
|
|
- ssc338q_apfpv
|
|
- ssc338q_apfpv_greg-generic-bu-eu
|
|
- ssc338q_apfpv_greg-generic-cu-eu
|
|
- ssc378qe_apfpv
|
|
|
|
# FPV
|
|
- hi3516ev200_fpv
|
|
- hi3516ev300_fpv
|
|
- hi3536dv100_fpv
|
|
- gk7205v200_fpv
|
|
- gk7205v210_fpv
|
|
- gk7205v300_fpv
|
|
- ssc30kq_fpv
|
|
- ssc338q_fpv
|
|
- ssc378qe_fpv
|
|
|
|
# Ruby
|
|
- ssc30kq_rubyfpv_generic
|
|
- ssc338q_rubyfpv_generic
|
|
- ssc338q_rubyfpv_thinker_internal_wifi
|
|
|
|
# LTE
|
|
- hi3516ev200_lte
|
|
- hi3516ev300_lte
|
|
- gk7205v200_lte
|
|
- gk7205v300_lte
|
|
|
|
# Venc
|
|
- gk7205v200_venc
|
|
- gk7205v210_venc
|
|
- gk7205v300_venc
|
|
|
|
# Mini
|
|
- hi3516cv300_mini
|
|
- hi3518ev200_mini
|
|
|
|
steps:
|
|
- name: Checkout source
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Prepare firmware
|
|
run: |
|
|
echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf
|
|
echo CACHE_DATE=$(date +%m) >> ${GITHUB_ENV}
|
|
INPUT=${{inputs.platform}}
|
|
MATRIX=$(echo ${{matrix.platform}} | cut -d_ -f1)
|
|
if [ -z ${INPUT} ] || [ ${INPUT} = ${MATRIX} ]; then
|
|
echo RUN=${MATRIX} >> ${GITHUB_ENV}
|
|
fi
|
|
|
|
- name: Setup ccache
|
|
if: env.RUN
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: /tmp/ccache
|
|
key: ${{matrix.platform}}-${{env.CACHE_DATE}}
|
|
|
|
# builder.sh does `rm -rf openipc` at the top of every run to force a
|
|
# clean re-clone of OpenIPC/firmware, which also nukes the default
|
|
# `openipc/output/dl/` directory Buildroot uses for downloaded source
|
|
# tarballs. Without a cache, every cron run re-downloads ~1-3 GB of
|
|
# tarballs from upstream mirrors — and any one of them randomly
|
|
# failing (e.g. cgit `snapshot/` URLs that regenerate tarballs per
|
|
# request with shifting sha256, like wireguard-tools on
|
|
# git.zx2c4.com) takes down the matrix entry for that board. See
|
|
# kaeru wireguard-zx2c4-tarball-regeneration-hash-drift for the
|
|
# specific incident this caching addresses.
|
|
#
|
|
# Cache to /tmp/builder-dl (outside the openipc/ tree so builder.sh's
|
|
# rm -rf doesn't touch it) and point Buildroot at it via BR2_DL_DIR
|
|
# env var (honored per Buildroot manual section "Location of source
|
|
# tarballs"). Mirrors OpenIPC/firmware/.github/workflows/build.yml's
|
|
# output/dl cache, adapted for builder's clean-clone behavior.
|
|
- name: Setup dl cache
|
|
if: env.RUN
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: /tmp/builder-dl
|
|
key: builder-dl-${{env.CACHE_DATE}}
|
|
restore-keys: builder-dl-
|
|
|
|
- name: Build firmware
|
|
if: env.RUN
|
|
run: |
|
|
export GIT_HASH=$(git rev-parse --short ${GITHUB_SHA})
|
|
export GIT_BRANCH=${GITHUB_REF_NAME}
|
|
echo GIT_HASH=${GIT_HASH} >> ${GITHUB_ENV}
|
|
echo GIT_BRANCH=${GIT_BRANCH} >> ${GITHUB_ENV}
|
|
|
|
mkdir -p /tmp/ccache
|
|
ln -s /tmp/ccache ${HOME}/.ccache
|
|
|
|
mkdir -p /tmp/builder-dl
|
|
export BR2_DL_DIR=/tmp/builder-dl
|
|
|
|
NAME=${{matrix.platform}}
|
|
# Retry budget for transient upstream toolchain/CDN flakes
|
|
# (matches OpenIPC/firmware/.github/workflows/build.yml).
|
|
backoffs="30 60 120 300 600 1200"
|
|
attempt=1
|
|
for sleep_for in $backoffs ""; do
|
|
bash builder.sh ${NAME} && break
|
|
if [ -z "$sleep_for" ]; then
|
|
echo "::error::build failed after ${attempt} attempts"
|
|
exit 1
|
|
fi
|
|
echo "::warning::attempt ${attempt} failed, retrying after ${sleep_for}s"
|
|
sleep "$sleep_for"
|
|
attempt=$((attempt + 1))
|
|
done
|
|
cd openipc
|
|
|
|
TIME=$(date -d @${SECONDS} +%M:%S)
|
|
echo TIME=${TIME} >> ${GITHUB_ENV}
|
|
COMMON=$(echo ${NAME} | awk -F_ '{print NF-1}')
|
|
|
|
NORFW=$(find output/images -name openipc*nor*)
|
|
if [ ! -z ${NORFW} ]; then
|
|
if [ ${COMMON} -eq 1 ]; then
|
|
echo NORFW=openipc/${NORFW} >> ${GITHUB_ENV}
|
|
else
|
|
mv ${NORFW} ../${NAME}-nor.tgz
|
|
echo NORFW=${NAME}-nor.tgz >> ${GITHUB_ENV}
|
|
fi
|
|
fi
|
|
|
|
NANDFW=$(find output/images -name openipc*nand*)
|
|
if [ ! -z ${NANDFW} ]; then
|
|
if [ ${COMMON} -eq 1 ]; then
|
|
echo NANDFW=openipc/${NANDFW} >> ${GITHUB_ENV}
|
|
else
|
|
mv ${NANDFW} ../${NAME}-nand.tgz
|
|
echo NANDFW=${NAME}-nand.tgz >> ${GITHUB_ENV}
|
|
fi
|
|
fi
|
|
|
|
if [ -z ${NORFW} ] && [ -z ${NANDFW} ]; then
|
|
exit 1
|
|
fi
|
|
|
|
- name: Build size report
|
|
if: env.NORFW || env.NANDFW
|
|
run: |
|
|
cd openipc
|
|
NAME=${{matrix.platform}}
|
|
make BOARD=${NAME} size-report || \
|
|
{ echo "::warning::size-report failed for ${NAME}"; exit 0; }
|
|
SIZES=$(find output/images -name 'sizes.*.json' | head -1)
|
|
if [ -z "${SIZES}" ]; then
|
|
exit 0
|
|
fi
|
|
# Mirror the .tgz rename trick: compound matrix entries
|
|
# (`<soc>_<variant>_<vendor>-<model>`) share `<soc>_<variant>` and
|
|
# would collide on the firmware-side `sizes.<soc>-<variant>.json`
|
|
# filename when uploaded to the same release tag. Rename to
|
|
# `sizes.<NAME>.json` so every compound device gets its own asset.
|
|
COMMON=$(echo ${NAME} | awk -F_ '{print NF-1}')
|
|
if [ ${COMMON} -eq 1 ]; then
|
|
echo "SIZES=openipc/${SIZES}" >> ${GITHUB_ENV}
|
|
else
|
|
mv ${SIZES} ../sizes.${NAME}.json
|
|
echo "SIZES=sizes.${NAME}.json" >> ${GITHUB_ENV}
|
|
fi
|
|
|
|
- name: Upload firmware (dated)
|
|
if: env.NORFW || env.NANDFW
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
tag_name: ${{ needs.preflight.outputs.build_id }}
|
|
prerelease: true
|
|
body: |
|
|
sha=${{ needs.preflight.outputs.head_sha }}
|
|
short=${{ needs.preflight.outputs.short_sha }}
|
|
built_at=${{ needs.preflight.outputs.built_at }}
|
|
files: |
|
|
${{env.NORFW}}
|
|
${{env.NANDFW}}
|
|
${{env.SIZES}}
|
|
|
|
- name: Upload firmware (rolling nightly)
|
|
if: env.NORFW || env.NANDFW
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
tag_name: nightly
|
|
body: |
|
|
sha=${{ needs.preflight.outputs.head_sha }}
|
|
short=${{ needs.preflight.outputs.short_sha }}
|
|
built_at=${{ needs.preflight.outputs.built_at }}
|
|
files: |
|
|
${{env.NORFW}}
|
|
${{env.NANDFW}}
|
|
${{env.SIZES}}
|
|
|
|
- name: Upload firmware (latest — legacy alias)
|
|
if: env.NORFW || env.NANDFW
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
tag_name: latest
|
|
files: |
|
|
${{env.NORFW}}
|
|
${{env.NANDFW}}
|
|
${{env.SIZES}}
|
|
|
|
- name: Send binary
|
|
if: env.NORFW
|
|
run: |
|
|
TG_MSG="Build: ${BUILD_ID}\nCommit: ${GIT_HASH}\nBranch: ${GIT_BRANCH}\nTime: ${TIME}\n\n"
|
|
TG_ICON="\xE2\x9C\x85 GitHub Actions"
|
|
TG_HEADER=$(echo -e ${TG_MSG}${TG_ICON})
|
|
TG_TOKEN=${{secrets.TELEGRAM_TOKEN_BOT_OPENIPC}}
|
|
TG_CHANNEL=${{secrets.TELEGRAM_CHANNEL_OPENIPC_DEV}}
|
|
HTTP=$(curl -s -o /dev/null -w %{http_code} https://api.telegram.org/bot${TG_TOKEN}/sendDocument -F chat_id=${TG_CHANNEL} -F caption="${TG_HEADER}" -F document=@${NORFW})
|
|
echo Telegram response: ${HTTP}
|