Skip to content

Build

Build #424

Workflow file for this run

name: Build
# All build/release/cleanup behavior reads its configuration from builder.yml.
# The pipeline is a matrix over builder.yml's `variants:` list:
# config -> check-updates -> build (matrix) -> prune
# The cron schedule below is the only knob that cannot be expressed in builder.yml
# (GitHub Actions cron values must be static strings in this file).
on:
workflow_dispatch:
inputs:
variant:
description: "Variant(s) to build"
type: choice
options:
- all
- edma-nss
default: all
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-26.04
timeout-minutes: 2
outputs:
matrix: ${{ steps.cfg.outputs.matrix }}
release_keep: ${{ steps.cfg.outputs.release_keep }}
artifact_retention_days: ${{ steps.cfg.outputs.artifact_retention_days }}
prefixes: ${{ steps.cfg.outputs.prefixes }}
steps:
- uses: actions/checkout@v7
- id: cfg
env:
EVENT_NAME: ${{ github.event_name }}
VARIANT_INPUT: ${{ github.event.inputs.variant }}
run: bash scripts/load-config.sh
check-updates:
name: Check upstreams
needs: config
runs-on: ubuntu-26.04
timeout-minutes: 5
permissions:
contents: read
env:
GH_TOKEN: ${{ github.token }}
outputs:
matrix: ${{ steps.check.outputs.matrix }}
has_builds: ${{ steps.check.outputs.has_builds }}
steps:
- uses: actions/checkout@v7
- id: check
env:
CONFIG_MATRIX: ${{ needs.config.outputs.matrix }}
EVENT_NAME: ${{ github.event_name }}
REPO: ${{ github.repository }}
run: bash scripts/check-updates.sh
build:
name: Build ${{ matrix.variant }} (${{ matrix.device }})
needs: [config, check-updates]
if: needs.check-updates.outputs.has_builds == 'true'
runs-on: ubuntu-26.04
timeout-minutes: 360
permissions:
contents: write
actions: read
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.check-updates.outputs.matrix) }}
env:
GH_TOKEN: ${{ github.token }}
steps:
- name: Install build dependencies
run: |
set -euo pipefail
# Pinned to the ubuntu-26.04 runner. OpenWrt main (as of May 2026) builds its own
# flex/bison/etc. host tools, so the host set is the minimal OpenWrt prerequisite list
# for Ubuntu 26.04. rsync is for prepare-build.sh's overlay step. Everything else
# (file, wget, unzip, yq, jq, gh) is preinstalled on the GitHub runner image.
sudo apt-get update
sudo apt-get install -y \
bzip2 g++ gawk gcc git glibc-source libncurses-dev make rsync
- name: Checkout OpenWrt source
uses: actions/checkout@v7
with:
repository: ${{ matrix.upstream_repo }}
ref: ${{ matrix.upstream_sha }}
fetch-depth: 0
path: openwrt
- name: Checkout builder repo
uses: actions/checkout@v7
with:
path: builder
- name: Prepare build environment
env:
OPENWRT_DIR: ${{ github.workspace }}/openwrt
BUILDER_REPO: ${{ github.workspace }}/builder
VARIANT: ${{ matrix.variant }}
DEVICE: ${{ matrix.device }}
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: ${{ matrix.variant }}-${{ matrix.device }}-images
path: openwrt/bin/targets/${{ matrix.target }}
if-no-files-found: error
retention-days: ${{ needs.config.outputs.artifact_retention_days }}
- name: Publish release
id: release
env:
VARIANT: ${{ matrix.variant }}
DEVICE: ${{ matrix.device }}
TARGET: ${{ matrix.target }}
RELEASE_PREFIX: ${{ matrix.release_prefix }}
UPSTREAM_REPO: ${{ matrix.upstream_repo }}
UPSTREAM_SHA: ${{ matrix.upstream_sha }}
NSS_SHA: ${{ matrix.nss_sha }}
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 — ${VARIANT}"
echo "- **Date**: $date"
echo "- **Variant**: \`${VARIANT}\`"
echo "- **Device**: \`${DEVICE}\`"
echo "- **Target**: \`${TARGET}\`"
echo "- **Upstream**: \`${UPSTREAM_REPO}@${UPSTREAM_SHA}\`"
if [[ -n "${NSS_SHA}" ]]; then
echo "- **NSS**: \`${NSS_SHA}\`"
fi
echo "- **Trigger**: \`${GITHUB_EVENT_NAME}\`"
} >release_notes.md
mapfile -t assets < <(find "openwrt/bin/targets/${TARGET}/" -type f -not -path "*/packages/*")
gh release create "$tag_name" \
--repo "$GITHUB_REPOSITORY" \
--title "OpenWrt ${VARIANT} $date" \
--notes-file release_notes.md \
"${assets[@]}"
{
echo "## Release (${VARIANT})"
echo "- tag: \`${tag_name}\`"
echo "- assets: ${#assets[@]}"
} >>"$GITHUB_STEP_SUMMARY"
prune:
name: Prune old releases
needs: [config, build]
runs-on: ubuntu-26.04
timeout-minutes: 5
permissions:
contents: write
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
KEEP: ${{ needs.config.outputs.release_keep }}
PREFIXES: ${{ needs.config.outputs.prefixes }}
steps:
- uses: actions/checkout@v7
- name: Prune each variant prefix
run: |
set -euo pipefail
while IFS= read -r prefix; do
[[ -z "$prefix" ]] && continue
echo "::group::prune $prefix"
PREFIX="$prefix" bash scripts/prune-releases.sh
echo "::endgroup::"
done <<< "$PREFIXES"