Build #1345
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: | |
| 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_cpplus-cp-unc-ta21l2c | |
| - 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: Refresh moving-ref package downloads | |
| if: env.RUN | |
| run: | | |
| # builder caches BR2_DL_DIR (/tmp/builder-dl) under a monthly key | |
| # (date +%m) and actions/cache only saves on a key miss, so the first build | |
| # of the month freezes it for weeks. Packages pinned to a moving ref keep a | |
| # constant download filename, so buildroot reuses the stale tarball — even | |
| # though builder re-clones firmware HEAD each run for freshness. Two forms: | |
| # - dash: <pkg>-<ref>.tar.gz e.g. majestic-webui-dist.tar.gz | |
| # - dot: <pkg>.<ref>.tar.bz2 e.g. majestic.t31.lite.master.tar.bz2 | |
| # The dot form is majestic's S3 tarball: it LOOKS S3-pinned but is a moving | |
| # `master` build re-uploaded every majestic CI run, with no .hash to force a | |
| # refetch — so it must be evicted too. (Empirically: a 06-14 nightly shipped a | |
| # ~2-week-old majestic-webui; later a t31 lite image shipped a pre-x-groups | |
| # majestic against the current webui — "No settings groups in schema".) Drop | |
| # both forms so buildroot re-fetches the current ref. Only genuinely | |
| # content-addressed tarballs (semver / SHA in the name) keep their cache. | |
| find /tmp/builder-dl -type f -regextype posix-extended \ | |
| -regex '.*[-.](HEAD|master|main|dist)\.tar\.(gz|bz2|xz)' \ | |
| -print -delete 2>/dev/null || true | |
| - 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} |