name: Build and push containers run-name: ${{ inputs.ref }} ${{ inputs.target }} env: FILE_HOST: https://mirror-03.infra.openwrt.org DOCKER_USER: ${{ secrets.DOCKER_USER }} DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }} QUAY_USER: ${{ secrets.QUAY_USER }} QUAY_TOKEN: ${{ secrets.QUAY_TOKEN }} on: # push: pull_request: schedule: # Rebuild the branch containers weekly so they do not drift away # from the published feeds; see the dispatch job below. - cron: "30 2 * * 1" workflow_dispatch: inputs: ref: description: "Tag or branch to deploy (empty for main)" default: "main" required: false target: description: "Single target to build (empty for all)" required: false file_host: description: "File host to use (empty for default)" required: false prefix: description: "Prefix for the image name (add '-' at the end)" required: false jobs: dispatch-scheduled-rebuilds: name: Dispatch scheduled rebuilds runs-on: ubuntu-latest if: github.event_name == 'schedule' permissions: actions: write steps: - name: Trigger a run for each maintained branch run: | for ref in main openwrt-24.10 openwrt-25.12; do gh workflow run containers.yml --repo "$GITHUB_REPOSITORY" -f ref="$ref" done env: GH_TOKEN: ${{ github.token }} generate_matrix: name: Set matrix runs-on: ubuntu-latest if: github.event_name != 'schedule' outputs: imagebuilders: ${{ steps.find_targets.outputs.imagebuilders }} rootfs: ${{ steps.find_targets.outputs.rootfs }} sdks: ${{ steps.find_targets.outputs.sdks }} ref: ${{ steps.find_targets.outputs.ref }} version: ${{ steps.find_targets.outputs.version }} version_path: ${{ steps.find_targets.outputs.version_path }} file_host: ${{ steps.find_targets.outputs.file_host }} run_setup: ${{ steps.find_targets.outputs.run_setup }} steps: - name: Set release if: github.event.inputs.ref != '' run: | export REF=${{ github.event.inputs.ref == 'master' && 'main' || github.event.inputs.ref }} echo "REF=$REF" >> "$GITHUB_ENV" case $REF in main) VERSION=SNAPSHOT echo "VERSION_PATH=snapshots" >> "$GITHUB_ENV" ;; openwrt-*) VERSION=${REF//openwrt-/}-SNAPSHOT echo "VERSION_PATH=releases/$VERSION" >> "$GITHUB_ENV" ;; v*) VERSION=${REF//v/} echo "VERSION_PATH=releases/$VERSION" >> "$GITHUB_ENV" echo "RUN_SETUP=1" >> "$GITHUB_ENV" ;; *) echo "No tag or branch found" exit 1 ;; esac echo "VERSION=$VERSION" >> "$GITHUB_ENV" - name: Checkout uses: actions/checkout@v7 with: repository: openwrt/openwrt ref: ${{ env.REF}} - name: Set targets id: find_targets run: | TARGET_FILTER="${{ github.event.inputs.target }}" # imagebuilders & rootfs JSON_IB='[' FIRST_IB=1 JSON_ROOTFS='[' FIRST_ROOTFS=1 while read -r line; do TARGET=$(echo "$line" | cut -d " " -f 1) ARCH=$(echo "$line" | cut -d " " -f 2) [[ $FIRST_IB -ne 1 ]] && JSON_IB="$JSON_IB"',' FIRST_IB=0 JSON_IB="$JSON_IB"'{"target":"'"$TARGET"'"}' case "$TARGET" in x86/*|arm*|malta/be|mvebu/cortexa9) [[ $FIRST_ROOTFS -ne 1 ]] && JSON_ROOTFS="$JSON_ROOTFS"',' FIRST_ROOTFS=0 JSON_ROOTFS="$JSON_ROOTFS"'{"target":"'"$TARGET"'","arch":"'"$ARCH"'"}' ;; esac done <<< $(perl ./scripts/dump-target-info.pl targets 2>/dev/null | ([[ -n "$TARGET_FILTER" ]] && grep -w "$TARGET_FILTER" || cat)) JSON_IB='{"include":'"$JSON_IB"']}' echo -e "\n---- imagebuilders ----\n" echo "$JSON_IB" | jq echo -e "\n---- imagebuilders ----\n" echo "imagebuilders=$JSON_IB" >> "$GITHUB_OUTPUT" JSON_ROOTFS='{"include":'"$JSON_ROOTFS"']}' echo -e "\n---- rootfs ----\n" echo "$JSON_ROOTFS" | jq echo -e "\n---- rootfs ----\n" echo "rootfs=$JSON_ROOTFS" >> "$GITHUB_OUTPUT" # sdks - one per target, first target per arch also gets the arch tag declare -A ARCH_SEEN JSON='[' FIRST=1 while read -r line; do TARGET=$(echo "$line" | cut -d " " -f 1) ARCH=$(echo "$line" | cut -d " " -f 2) TARGET_TAG="${TARGET//\//-}" TAGS="$TARGET_TAG" if [ -z "${ARCH_SEEN[$ARCH]+x}" ]; then TAGS="$TARGET_TAG\n$ARCH" ARCH_SEEN[$ARCH]=1 fi [[ $FIRST -ne 1 ]] && JSON="$JSON"',' FIRST=0 JSON="$JSON"'{"target":"'"$TARGET"'","tags":"'"$TAGS"'"}' done <<< $(perl ./scripts/dump-target-info.pl targets 2>/dev/null | ([[ -n "$TARGET_FILTER" ]] && grep -w "$TARGET_FILTER" || cat)) JSON='{"include":'"$JSON"']}' echo -e "\n---- sdks ----\n" echo "$JSON" | jq echo -e "\n---- sdks ----\n" echo "sdks=$JSON" >> "$GITHUB_OUTPUT" echo "ref=${REF:-main}" >> "$GITHUB_OUTPUT" echo "version=${VERSION:-SNAPSHOT}" >> "$GITHUB_OUTPUT" echo "version_path=${VERSION_PATH:-snapshots}" >> "$GITHUB_OUTPUT" echo "run_setup=${RUN_SETUP:-0}" >> "$GITHUB_OUTPUT" FILE_HOST=${{ needs.generate_matrix.outputs.file_host }} echo "file_host=${FILE_HOST:-mirror-03.infra.openwrt.org}" >> "$GITHUB_OUTPUT" push-imagebuilder-container: name: ImageBuilder runs-on: ubuntu-latest needs: generate_matrix strategy: fail-fast: False matrix: ${{fromJson(needs.generate_matrix.outputs.imagebuilders)}} steps: - name: Login to GitHub Container Registry if: github.event_name != 'pull_request' uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Login to Docker.io Container Registry if: github.event_name != 'pull_request' && env.DOCKER_USER != '' && env.DOCKER_TOKEN != '' uses: docker/login-action@v4 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_TOKEN }} - name: Login to Quay.io Container Registry if: github.event_name != 'pull_request' && env.QUAY_USER != '' && env.QUAY_TOKEN != '' uses: docker/login-action@v4 with: registry: quay.io username: ${{ secrets.QUAY_USER }} password: ${{ secrets.QUAY_TOKEN }} - name: Docker meta id: meta uses: docker/metadata-action@v6 with: images: | ghcr.io/${{ github.repository_owner }}/imagebuilder ${{ env.DOCKER_USER != '' && format('docker.io/{0}/imagebuilder', env.DOCKER_USER) || '' }} ${{ env.QUAY_USER != '' && format('quay.io/{0}/imagebuilder', env.QUAY_USER) || '' }} flavor: | latest=false prefix=${{ github.event.inputs.prefix }} tags: | ${{ matrix.target }}-${{ needs.generate_matrix.outputs.ref }} ${{ matrix.target }}-${{ needs.generate_matrix.outputs.version }} ${{ matrix.target }}-master,enable=${{ needs.generate_matrix.outputs.ref == 'main' }} ${{ matrix.target }},enable=${{ needs.generate_matrix.outputs.version == 'SNAPSHOT' }} latest,enable=${{ needs.generate_matrix.outputs.version == 'SNAPSHOT' && matrix.target == 'x86/64'}} - name: Build id: build uses: docker/build-push-action@v7 with: no-cache: true push: false tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-args: | DOWNLOAD_FILE=imagebuilder-.*x86_64.tar.[xz|zst] VERSION_PATH=${{ needs.generate_matrix.outputs.version_path }} TARGET=${{ matrix.target }} FILE_HOST=${{ needs.generate_matrix.outputs.file_host }} RUN_SETUP=${{ needs.generate_matrix.outputs.run_setup }} - name: Smoke test run: | docker run ${{ steps.build.outputs.imageid }} \ bash -c ' \ cd $HOME && \ bash setup.sh && \ make image PACKAGES=coreutils-echo \ ' - name: Push if: github.event_name != 'pull_request' uses: docker/build-push-action@v7 with: push: true no-cache: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-args: | DOWNLOAD_FILE=imagebuilder-.*x86_64.tar.[xz|zst] VERSION_PATH=${{ needs.generate_matrix.outputs.version_path }} TARGET=${{ matrix.target }} FILE_HOST=${{ needs.generate_matrix.outputs.file_host }} RUN_SETUP=${{ needs.generate_matrix.outputs.run_setup }} - name: Cleanup Docker containers run: docker system prune -f push-sdk-container: name: SDK runs-on: ubuntu-latest needs: generate_matrix strategy: fail-fast: False matrix: ${{fromJson(needs.generate_matrix.outputs.sdks)}} steps: - name: Login to GitHub Container Registry if: github.event_name != 'pull_request' uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Login to Docker.io Container Registry if: github.event_name != 'pull_request' && env.DOCKER_USER != '' && env.DOCKER_TOKEN != '' uses: docker/login-action@v4 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_TOKEN }} - name: Login to Quay.io Container Registry if: github.event_name != 'pull_request' && env.QUAY_USER != '' && env.QUAY_TOKEN != '' uses: docker/login-action@v4 with: registry: quay.io username: ${{ secrets.QUAY_USER }} password: ${{ secrets.QUAY_TOKEN }} - name: Docker meta (tag or branch) id: meta_ref uses: docker/metadata-action@v6 with: images: | ghcr.io/${{ github.repository_owner }}/sdk ${{ env.DOCKER_USER != '' && format('docker.io/{0}/sdk', env.DOCKER_USER) || '' }} ${{ env.QUAY_USER != '' && format('quay.io/{0}/sdk', env.QUAY_USER) || '' }} flavor: | latest=false prefix=${{ github.event.inputs.prefix }} suffix=-${{ needs.generate_matrix.outputs.ref }} tags: ${{ matrix.tags }} - name: Docker meta (version) id: meta_version uses: docker/metadata-action@v6 with: images: | ghcr.io/${{ github.repository_owner }}/sdk ${{ env.DOCKER_USER != '' && format('docker.io/{0}/sdk', env.DOCKER_USER) || '' }} ${{ env.QUAY_USER != '' && format('quay.io/{0}/sdk', env.QUAY_USER) || '' }} flavor: | latest=false prefix=${{ github.event.inputs.prefix }} suffix=-${{ needs.generate_matrix.outputs.version }} tags: ${{ matrix.tags }} - name: Docker meta (master) if: needs.generate_matrix.outputs.ref == 'main' id: meta_master uses: docker/metadata-action@v6 with: images: | ghcr.io/${{ github.repository_owner }}/sdk ${{ env.DOCKER_USER != '' && format('docker.io/{0}/sdk', env.DOCKER_USER) || '' }} ${{ env.QUAY_USER != '' && format('quay.io/{0}/sdk', env.QUAY_USER) || '' }} flavor: | latest=false prefix=${{ github.event.inputs.prefix }} suffix=-master tags: ${{ matrix.tags }} - name: Docker meta (target and arch) if: needs.generate_matrix.outputs.version == 'SNAPSHOT' id: meta_target_arch uses: docker/metadata-action@v6 with: images: | ghcr.io/${{ github.repository_owner }}/sdk ${{ env.DOCKER_USER != '' && format('docker.io/{0}/sdk', env.DOCKER_USER) || '' }} ${{ env.QUAY_USER != '' && format('quay.io/{0}/sdk', env.QUAY_USER) || '' }} flavor: | latest=false prefix=${{ github.event.inputs.prefix }} tags: ${{ matrix.tags }} - name: Docker meta (latest) if: needs.generate_matrix.outputs.version == 'SNAPSHOT' && matrix.target == 'x86/64' id: meta_latest uses: docker/metadata-action@v6 with: images: | ghcr.io/${{ github.repository_owner }}/sdk ${{ env.DOCKER_USER != '' && format('docker.io/{0}/sdk', env.DOCKER_USER) || '' }} ${{ env.QUAY_USER != '' && format('quay.io/{0}/sdk', env.QUAY_USER) || '' }} tags: latest - name: Build id: build uses: docker/build-push-action@v7 with: no-cache: true push: false tags: | ${{ steps.meta_ref.outputs.tags }} ${{ steps.meta_version.outputs.tags }} ${{ steps.meta_master.outputs.tags }} ${{ steps.meta_target_arch.outputs.tags }} ${{ steps.meta_latest.outputs.tags }} build-args: | DOWNLOAD_FILE=sdk-.*.Linux-x86_64.tar.[xz|zst] VERSION_PATH=${{ needs.generate_matrix.outputs.version_path }} TARGET=${{ matrix.target }} FILE_HOST=${{ needs.generate_matrix.outputs.file_host }} RUN_SETUP=${{ needs.generate_matrix.outputs.run_setup }} labels: ${{ steps.meta_ref.outputs.labels }} - name: Smoke test run: | docker run --rm ${{ steps.build.outputs.imageid }} \ bash -c ' \ cd $HOME && \ bash ./setup.sh && \ make defconfig && \ sed -i -E "s;git.openwrt.org/(feed|project|openwrt);github.com/openwrt;" feeds.conf.default && \ ./scripts/feeds update base && \ ./scripts/feeds install urngd && \ make package/urngd/{clean,compile} V=s -j$(nproc) && \ find ./bin/packages -name urngd*.?pk | grep ^./bin/packages/.*urngd \ ' - name: Push if: github.event_name != 'pull_request' uses: docker/build-push-action@v7 with: push: true no-cache: true tags: | ${{ steps.meta_ref.outputs.tags }} ${{ steps.meta_version.outputs.tags }} ${{ steps.meta_master.outputs.tags }} ${{ steps.meta_target_arch.outputs.tags }} ${{ steps.meta_latest.outputs.tags }} build-args: | DOWNLOAD_FILE=sdk-.*.Linux-x86_64.tar.[xz|zst] VERSION_PATH=${{ needs.generate_matrix.outputs.version_path }} TARGET=${{ matrix.target }} FILE_HOST=${{ needs.generate_matrix.outputs.file_host }} RUN_SETUP=${{ needs.generate_matrix.outputs.run_setup }} labels: ${{ steps.meta_ref.outputs.labels }} - name: Cleanup Docker containers run: docker system prune -f push-rootfs-container: name: RootFS runs-on: ubuntu-latest needs: generate_matrix if: needs.generate_matrix.outputs.rootfs != '{"include":[]}' strategy: fail-fast: False matrix: ${{fromJson(needs.generate_matrix.outputs.rootfs)}} steps: - name: Set up QEMU run: | sudo apt-get update sudo apt-get install -y qemu-user-static binfmt-support sudo update-binfmts --import - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - name: Login to GitHub Container Registry if: github.event_name != 'pull_request' uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Login to Docker.io Container Registry if: github.event_name != 'pull_request' && env.DOCKER_USER != '' && env.DOCKER_TOKEN != '' uses: docker/login-action@v4 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_TOKEN }} - name: Login to Quay.io Container Registry if: github.event_name != 'pull_request' && env.QUAY_USER != '' && env.QUAY_TOKEN != '' uses: docker/login-action@v4 with: registry: quay.io username: ${{ secrets.QUAY_USER }} password: ${{ secrets.QUAY_TOKEN }} - name: Docker meta id: meta uses: docker/metadata-action@v6 with: images: | ghcr.io/${{ github.repository_owner }}/rootfs ${{ env.DOCKER_USER != '' && format('docker.io/{0}/rootfs', env.DOCKER_USER) || '' }} ${{ env.QUAY_USER != '' && format('quay.io/{0}/rootfs', env.QUAY_USER) || '' }} flavor: | latest=false prefix=${{ github.event.inputs.prefix }} tags: | ${{ matrix.target }}-${{ needs.generate_matrix.outputs.ref }} ${{ matrix.target }}-${{ needs.generate_matrix.outputs.version }} ${{ matrix.target }}-master,enable=${{ needs.generate_matrix.outputs.ref == 'main' }} ${{ matrix.target }},enable=${{ needs.generate_matrix.outputs.version == 'SNAPSHOT' }} ${{ matrix.arch }}-${{ needs.generate_matrix.outputs.ref }} ${{ matrix.arch }}-${{ needs.generate_matrix.outputs.version }} ${{ matrix.arch }}-master,enable=${{ needs.generate_matrix.outputs.ref == 'main' }} ${{ matrix.arch }},enable=${{ needs.generate_matrix.outputs.version == 'SNAPSHOT' }} latest,enable=${{ needs.generate_matrix.outputs.version == 'SNAPSHOT' && matrix.target == 'x86/64'}} - name: Generate build args id: build_args run: | TARGET='${{ matrix.target }}' echo "args<> $GITHUB_OUTPUT - name: Build id: build uses: docker/build-push-action@v7 with: no-cache: true push: false tags: ${{ steps.meta.outputs.tags }} load: true file: Dockerfile.rootfs build-args: ${{ steps.build_args.outputs.args }} labels: ${{ steps.meta.outputs.labels }} platforms: linux/${{ matrix.arch }} - name: Smoke test run: docker run --platform=linux/${{ matrix.arch }} ${{ steps.build.outputs.imageid }} uname -m - name: Push if: github.event_name != 'pull_request' uses: docker/build-push-action@v7 with: no-cache: true push: true tags: ${{ steps.meta.outputs.tags }} file: Dockerfile.rootfs build-args: ${{ steps.build_args.outputs.args }} labels: ${{ steps.meta.outputs.labels }} platforms: linux/${{ matrix.arch }} - name: Cleanup Docker containers run: docker system prune -f