Build #201
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 | |
| # 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 |