Skip to content

Build

Build #216

Workflow file for this run

name: Build
# All build/release/cleanup behavior reads its configuration from builder.yml.
# The cron schedule below is the only knob that cannot be expressed there
# (GitHub Actions cron values must be static strings in this file).
on:
workflow_dispatch:
push:
branches: [main]
paths:
- builder.yml
- 'devices/**'
- 'common/**'
- 'patches/**'
- 'scripts/**'
- '.github/workflows/build.yml'
schedule:
- cron: "0 */2 * * *"
concurrency:
group: build-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: read
jobs:
config:
name: Load builder.yml
runs-on: ubuntu-latest
timeout-minutes: 2
outputs:
upstream_repo: ${{ steps.cfg.outputs.upstream_repo }}
upstream_branch: ${{ steps.cfg.outputs.upstream_branch }}
nss_repo: ${{ steps.cfg.outputs.nss_repo }}
nss_branch: ${{ steps.cfg.outputs.nss_branch }}
device: ${{ steps.cfg.outputs.device }}
device_dir: ${{ steps.cfg.outputs.device_dir }}
release_prefix: ${{ steps.cfg.outputs.release_prefix }}
release_keep: ${{ steps.cfg.outputs.release_keep }}
artifact_retention_days: ${{ steps.cfg.outputs.artifact_retention_days }}
feeds_lines: ${{ steps.cfg.outputs.feeds_lines }}
steps:
- uses: actions/checkout@v6
- id: cfg
run: bash scripts/load-config.sh
check-updates:
name: Check upstream
needs: config
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
env:
GH_TOKEN: ${{ github.token }}
UPSTREAM_REPO: ${{ needs.config.outputs.upstream_repo }}
UPSTREAM_BRANCH: ${{ needs.config.outputs.upstream_branch }}
NSS_REPO: ${{ needs.config.outputs.nss_repo }}
NSS_BRANCH: ${{ needs.config.outputs.nss_branch }}
outputs:
build_required: ${{ steps.check.outputs.build_required }}
main_sha: ${{ steps.check.outputs.main_sha }}
nss_sha: ${{ steps.check.outputs.nss_sha }}
steps:
- id: check
run: |
set -euo pipefail
main_sha=$(gh api "repos/${UPSTREAM_REPO}/commits/${UPSTREAM_BRANCH}" --jq .sha)
nss_sha=$(gh api "repos/${NSS_REPO}/commits/${NSS_BRANCH}" --jq .sha)
latest_release_body=$(gh release view --repo "${GITHUB_REPOSITORY}" --json body --jq .body 2>/dev/null || echo "")
build_required=true
if [[ "${GITHUB_EVENT_NAME}" != "workflow_dispatch" ]] \
&& [[ "$latest_release_body" == *"$main_sha"* ]] \
&& [[ "$latest_release_body" == *"$nss_sha"* ]]; then
build_required=false
fi
{
echo "## Upstream check"
echo "- upstream: \`${UPSTREAM_REPO}@${UPSTREAM_BRANCH}\` -> \`${main_sha}\`"
echo "- nss: \`${NSS_REPO}@${NSS_BRANCH}\` -> \`${nss_sha}\`"
echo "- build_required: **${build_required}**"
} >>"$GITHUB_STEP_SUMMARY"
{
echo "build_required=$build_required"
echo "main_sha=$main_sha"
echo "nss_sha=$nss_sha"
} >>"$GITHUB_OUTPUT"
build:
name: Build firmware
needs: [config, check-updates]
if: needs.check-updates.outputs.build_required == 'true'
runs-on: ubuntu-latest
timeout-minutes: 360
permissions:
contents: write
actions: read
env:
GH_TOKEN: ${{ github.token }}
MAIN_SHA: ${{ needs.check-updates.outputs.main_sha }}
NSS_SHA: ${{ needs.check-updates.outputs.nss_sha }}
DEVICE: ${{ needs.config.outputs.device }}
DEVICE_DIR: ${{ needs.config.outputs.device_dir }}
RELEASE_PREFIX: ${{ needs.config.outputs.release_prefix }}
ARTIFACT_RETENTION_DAYS: ${{ needs.config.outputs.artifact_retention_days }}
FEEDS_LINES: ${{ needs.config.outputs.feeds_lines }}
outputs:
release_tag: ${{ steps.release.outputs.release_tag }}
steps:
- name: Install build dependencies
run: |
set -euo pipefail
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
build-essential clang flex bison g++ gawk gcc-multilib g++-multilib gettext git \
libncurses5-dev libssl-dev python3-setuptools rsync swig unzip zlib1g-dev file wget
- name: Checkout OpenWrt source
uses: actions/checkout@v6
with:
repository: ${{ needs.config.outputs.upstream_repo }}
ref: ${{ env.MAIN_SHA }}
fetch-depth: 0
path: openwrt
- name: Checkout builder repo
uses: actions/checkout@v6
with:
path: builder
- name: Prepare build environment
env:
OPENWRT_DIR: ${{ github.workspace }}/openwrt
BUILDER_REPO: ${{ github.workspace }}/builder
run: bash builder/scripts/prepare-build.sh
- name: Set reproducible-build env
working-directory: openwrt
run: |
set -euo pipefail
{
echo "SOURCE_DATE_EPOCH=$(git show -s --format=%ct HEAD)"
echo "TZ=UTC"
echo "LC_ALL=C"
echo "KBUILD_BUILD_USER=builder"
echo "KBUILD_BUILD_HOST=github"
} >>"$GITHUB_ENV"
- name: Download sources
working-directory: openwrt
run: |
set -euo pipefail
for attempt in 1 2 3; do
make download -j"$(nproc)" V=s && break
echo "Download attempt $attempt failed; retrying..."
sleep 5
done
- name: Build
working-directory: openwrt
run: |
set -euo pipefail
if ! make -j"$(nproc)"; then
echo "::warning::Parallel build failed; retrying single-threaded for diagnostics"
make -j1 V=s
fi
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: ${{ needs.config.outputs.device }}-images
path: openwrt/bin/targets/qualcommax/ipq807x
if-no-files-found: error
retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }}
- name: Publish release
id: release
run: |
set -euo pipefail
date=$(date -u +%F)
timestamp=$(date -u +%Y%m%dT%H%M%SZ)
tag_name="${RELEASE_PREFIX}-${timestamp}-${GITHUB_RUN_ID}"
echo "release_tag=$tag_name" >>"$GITHUB_OUTPUT"
{
echo "## OpenWrt Build"
echo "- **Date**: $date"
echo "- **Device**: \`${DEVICE}\`"
echo "- **Upstream**: \`${MAIN_SHA}\`"
echo "- **NSS**: \`${NSS_SHA}\`"
echo "- **Trigger**: \`${GITHUB_EVENT_NAME}\`"
} >release_notes.md
mapfile -t assets < <(find openwrt/bin/targets/qualcommax/ipq807x/ -type f -not -path "*/packages/*")
gh release create "$tag_name" \
--repo "$GITHUB_REPOSITORY" \
--title "OpenWrt Build $date" \
--notes-file release_notes.md \
"${assets[@]}"
{
echo "## Release"
echo "- tag: \`${tag_name}\`"
echo "- assets: ${#assets[@]}"
} >>"$GITHUB_STEP_SUMMARY"
prune:
name: Prune old releases
needs: [config, build]
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: write
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
KEEP: ${{ needs.config.outputs.release_keep }}
CURRENT_TAG: ${{ needs.build.outputs.release_tag }}
steps:
- uses: actions/checkout@v6
- run: bash scripts/prune-releases.sh