From b0a097b6c1239baca0a1e97834f37a642fc38c00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cerm=C3=A1k?= Date: Tue, 24 Mar 2026 16:51:41 +0100 Subject: [PATCH 1/4] Modernize and migrate builder workflow to new builder actions Replace the monolithic builder container with the new builder GitHub Actions. Split the workflow into a main orchestrator (`builder.yaml`) that detects changed apps, and a reusable per-app workflow (`build-app.yaml`) that handles single app build. Also, replace unmaintained `jitterbit/get-changed-files` with `tj-actions/changed-files`. Closes home-assistant/epics#35 --- .github/workflows/build-app.yaml | 97 +++++++++++++++++++++++ .github/workflows/builder.yaml | 129 +++++++++++-------------------- README.md | 14 ++-- example/Dockerfile | 26 +++++-- example/build.yaml | 11 --- example/config.yaml | 2 +- 6 files changed, 173 insertions(+), 106 deletions(-) create mode 100644 .github/workflows/build-app.yaml delete mode 100644 example/build.yaml diff --git a/.github/workflows/build-app.yaml b/.github/workflows/build-app.yaml new file mode 100644 index 00000000..344fe64d --- /dev/null +++ b/.github/workflows/build-app.yaml @@ -0,0 +1,97 @@ +name: Build app + +on: + workflow_call: + inputs: + app: + required: true + type: string + publish: + required: true + type: boolean + +jobs: + prepare: + name: Prepare ${{ inputs.app }} + if: github.repository == 'home-assistant/addons-example' + runs-on: ubuntu-latest + outputs: + architectures: ${{ steps.info.outputs.architectures }} + build_matrix: ${{ steps.matrix.outputs.matrix }} + image_name: ${{ steps.split.outputs.image_name }} + registry_prefix: ${{ steps.split.outputs.registry_prefix }} + version: ${{ steps.info.outputs.version }} + steps: + - name: Check out the repository + uses: actions/checkout@v6.0.2 + + - name: Get app information + id: info + uses: home-assistant/actions/helpers/info@master + with: + path: "./${{ inputs.app }}" + + - name: Split image name + id: split + run: | + image="${{ steps.info.outputs.image }}" + echo "image_name=${image##*/}" >> "$GITHUB_OUTPUT" + echo "registry_prefix=${image%/*}" >> "$GITHUB_OUTPUT" + + - name: Prepare build matrix + id: matrix + uses: home-assistant/builder/actions/prepare-multi-arch-matrix@2026.03.2 + with: + architectures: ${{ steps.info.outputs.architectures }} + image-name: ${{ steps.split.outputs.image_name }} + registry-prefix: ${{ steps.split.outputs.registry_prefix }} + + build: + name: Build ${{ matrix.arch }} ${{ inputs.app }} + needs: prepare + runs-on: ${{ matrix.os }} + permissions: + contents: read + id-token: write + packages: write + strategy: + fail-fast: false + matrix: ${{ fromJSON(needs.prepare.outputs.build_matrix) }} + steps: + - name: Check out the repository + uses: actions/checkout@v6.0.2 + with: + persist-credentials: false + + - name: Build image + uses: home-assistant/builder/actions/build-image@2026.03.2 + with: + arch: ${{ matrix.arch }} + container-registry-password: ${{ secrets.GITHUB_TOKEN }} + context: "./${{ inputs.app }}" + image: ${{ matrix.image }} + image-tags: | + ${{ needs.prepare.outputs.version }} + latest + push: ${{ inputs.publish }} + version: ${{ needs.prepare.outputs.version }} + + manifest: + name: Publish multi-arch manifest + needs: [prepare, build] + if: inputs.publish + runs-on: ubuntu-latest + permissions: + id-token: write + packages: write + steps: + - name: Publish multi-arch manifest + uses: home-assistant/builder/actions/publish-multi-arch-manifest@2026.03.2 + with: + architectures: ${{ needs.prepare.outputs.architectures }} + container-registry-password: ${{ secrets.GITHUB_TOKEN }} + image-name: ${{ needs.prepare.outputs.image_name }} + image-tags: | + ${{ needs.prepare.outputs.version }} + latest + registry-prefix: ${{ needs.prepare.outputs.registry_prefix }} diff --git a/.github/workflows/builder.yaml b/.github/workflows/builder.yaml index cef45c92..e13e96ed 100644 --- a/.github/workflows/builder.yaml +++ b/.github/workflows/builder.yaml @@ -1,117 +1,80 @@ name: Builder env: - BUILD_ARGS: "--test" - MONITORED_FILES: "build.yaml config.yaml Dockerfile rootfs" + MONITORED_FILES: "config.json config.yaml config.yml Dockerfile rootfs" on: - push: + pull_request: branches: - main - pull_request: + push: branches: - main +permissions: + contents: read + jobs: init: - runs-on: ubuntu-latest name: Initialize builds + runs-on: ubuntu-latest outputs: - changed_addons: ${{ steps.changed_addons.outputs.addons }} - changed: ${{ steps.changed_addons.outputs.changed }} + changed: ${{ steps.filter.outputs.changed }} + changed_apps: ${{ steps.filter.outputs.changed_apps }} steps: - name: Check out the repository uses: actions/checkout@v6.0.2 - name: Get changed files id: changed_files - uses: jitterbit/get-changed-files@v1 + uses: tj-actions/changed-files@v47 - name: Find app directories - id: addons + id: apps uses: home-assistant/actions/helpers/find-addons@master - - name: Get changed apps - id: changed_addons + - name: Filter changed apps + id: filter + env: + APPS: ${{ steps.apps.outputs.addons }} + CHANGED_FILES: ${{ steps.changed_files.outputs.all_changed_files }} run: | - declare -a changed_addons - for addon in ${{ steps.addons.outputs.addons }}; do - if [[ "${{ steps.changed_files.outputs.all }}" =~ $addon ]]; then - for file in ${{ env.MONITORED_FILES }}; do - if [[ "${{ steps.changed_files.outputs.all }}" =~ $addon/$file ]]; then - if [[ ! "${changed_addons[@]}" =~ $addon ]]; then - changed_addons+=("\"${addon}\","); - fi - fi - done - fi - done + changed_apps=() - changed=$(echo ${changed_addons[@]} | rev | cut -c 2- | rev) + # If the workflow file itself changed, rebuild all apps + if [[ "${CHANGED_FILES}" =~ \.github/workflows/(builder|build-app)\.yaml ]]; then + changed_apps=(${APPS}) + else + for app in ${APPS}; do + for file in ${MONITORED_FILES}; do + if [[ "${CHANGED_FILES}" =~ ${app}/${file} ]]; then + changed_apps+=("${app}") + break + fi + done + done + fi - if [[ -n ${changed} ]]; then - echo "Changed apps: $changed"; - echo "changed=true" >> $GITHUB_OUTPUT; - echo "addons=[$changed]" >> $GITHUB_OUTPUT; + if [[ ${#changed_apps[@]} -gt 0 ]]; then + echo "changed=true" >> "$GITHUB_OUTPUT" + echo "changed_apps=$(jq -nc '$ARGS.positional' --args "${changed_apps[@]}")" >> "$GITHUB_OUTPUT" else - echo "No app had any monitored files changed (${{ env.MONITORED_FILES }})"; + echo "changed=false" >> "$GITHUB_OUTPUT" fi - build: + + build-app: needs: init - runs-on: ubuntu-latest if: needs.init.outputs.changed == 'true' - name: Build ${{ matrix.arch }} ${{ matrix.addon }} app - strategy: - matrix: - addon: ${{ fromJson(needs.init.outputs.changed_addons) }} - arch: ["aarch64", "amd64"] permissions: contents: read + id-token: write packages: write - - steps: - - name: Check out repository - uses: actions/checkout@v6.0.2 - - - name: Get information - id: info - uses: home-assistant/actions/helpers/info@master - with: - path: "./${{ matrix.addon }}" - - - name: Check if app should be built - id: check - run: | - if [[ "${{ steps.info.outputs.image }}" == "null" ]]; then - echo "Image property is not defined, skipping build" - echo "build_arch=false" >> $GITHUB_OUTPUT; - elif [[ "${{ steps.info.outputs.architectures }}" =~ ${{ matrix.arch }} ]]; then - echo "build_arch=true" >> $GITHUB_OUTPUT; - echo "image=$(echo ${{ steps.info.outputs.image }} | cut -d'/' -f3)" >> $GITHUB_OUTPUT; - if [[ -z "${{ github.head_ref }}" ]] && [[ "${{ github.event_name }}" == "push" ]]; then - echo "BUILD_ARGS=" >> $GITHUB_ENV; - fi - else - echo "${{ matrix.arch }} is not a valid arch for ${{ matrix.addon }}, skipping build"; - echo "build_arch=false" >> $GITHUB_OUTPUT; - fi - - - name: Login to GitHub Container Registry - if: env.BUILD_ARGS != '--test' - uses: docker/login-action@v4.0.0 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build ${{ matrix.addon }} app - if: steps.check.outputs.build_arch == 'true' - uses: home-assistant/builder@2026.02.1 - with: - args: | - ${{ env.BUILD_ARGS }} \ - --${{ matrix.arch }} \ - --target /data/${{ matrix.addon }} \ - --image "${{ steps.check.outputs.image }}" \ - --docker-hub "ghcr.io/${{ github.repository_owner }}" \ - --addon + strategy: + fail-fast: false + matrix: + app: ${{ fromJSON(needs.init.outputs.changed_apps) }} + uses: ./.github/workflows/build-app.yaml + with: + app: ${{ matrix.app }} + publish: ${{ github.event_name == 'push' }} + secrets: inherit diff --git a/README.md b/README.md index 7e0dadec..761b8177 100644 --- a/README.md +++ b/README.md @@ -20,18 +20,20 @@ _Example app to use as a blueprint for new apps._ diff --git a/example/Dockerfile b/example/Dockerfile index caea653f..2496e677 100644 --- a/example/Dockerfile +++ b/example/Dockerfile @@ -1,12 +1,28 @@ # https://developers.home-assistant.io/docs/apps/configuration#app-dockerfile -ARG BUILD_FROM -FROM $BUILD_FROM +ARG BUILD_FROM=ghcr.io/home-assistant/base:3.23 +FROM ${BUILD_FROM} # Execute during the build of the image -ARG TEMPIO_VERSION BUILD_ARCH +ARG TEMPIO_VERSION=2021.09.0 +ARG TARGETARCH RUN \ - curl -sSLf -o /usr/bin/tempio \ - "https://github.com/home-assistant/tempio/releases/download/${TEMPIO_VERSION}/tempio_${BUILD_ARCH}" + if [ -z "${TARGETARCH}" ]; then \ + echo "TARGETARCH is not set, please use Docker BuildKit for the build." && exit 1; \ + fi \ + && case "${TARGETARCH}" in \ + amd64) tempio_arch="amd64" ;; \ + arm64) tempio_arch="aarch64" ;; \ + *) echo "Unsupported TARGETARCH: ${TARGETARCH}" && exit 1 ;; \ + esac \ + && curl -sSLf -o /usr/bin/tempio \ + "https://github.com/home-assistant/tempio/releases/download/${TEMPIO_VERSION}/tempio_${tempio_arch}" # Copy root filesystem COPY rootfs / + +LABEL \ + io.hass.type="addon" \ + org.opencontainers.image.title="Home Assistant App: Example app" \ + org.opencontainers.image.description="Example app to use as a blueprint for new apps." \ + org.opencontainers.image.source="https://github.com/home-assistant/apps-example" \ + org.opencontainers.image.licenses="Apache License 2.0" diff --git a/example/build.yaml b/example/build.yaml deleted file mode 100644 index b80f868d..00000000 --- a/example/build.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# https://developers.home-assistant.io/docs/apps/configuration#app-dockerfile -build_from: - aarch64: "ghcr.io/home-assistant/aarch64-base:3.23" - amd64: "ghcr.io/home-assistant/amd64-base:3.23" -labels: - org.opencontainers.image.title: "Home Assistant App: Example app" - org.opencontainers.image.description: "Example app to use as a blueprint for new apps." - org.opencontainers.image.source: "https://github.com/home-assistant/apps-example" - org.opencontainers.image.licenses: "Apache License 2.0" -args: - TEMPIO_VERSION: "2021.09.0" diff --git a/example/config.yaml b/example/config.yaml index a97e4f28..0a03bc90 100644 --- a/example/config.yaml +++ b/example/config.yaml @@ -14,4 +14,4 @@ options: message: "Hello world..." schema: message: "str?" -image: "ghcr.io/home-assistant/{arch}-app-example" +image: "ghcr.io/home-assistant/app-example" From 7ee3492594965e402b7ff81d1f55833a0f2ebb0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cerm=C3=A1k?= Date: Tue, 24 Mar 2026 18:13:13 +0100 Subject: [PATCH 2/4] Update repo name --- .github/workflows/build-app.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-app.yaml b/.github/workflows/build-app.yaml index 344fe64d..8242feee 100644 --- a/.github/workflows/build-app.yaml +++ b/.github/workflows/build-app.yaml @@ -13,7 +13,7 @@ on: jobs: prepare: name: Prepare ${{ inputs.app }} - if: github.repository == 'home-assistant/addons-example' + if: github.repository == 'home-assistant/apps-example' runs-on: ubuntu-latest outputs: architectures: ${{ steps.info.outputs.architectures }} From 14422621e5a7c3747c6064c61a7bdf697519a51d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cerm=C3=A1k?= Date: Tue, 24 Mar 2026 18:19:42 +0100 Subject: [PATCH 3/4] Strip quotes from version obtained from config --- .github/workflows/build-app.yaml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-app.yaml b/.github/workflows/build-app.yaml index 8242feee..aa16de91 100644 --- a/.github/workflows/build-app.yaml +++ b/.github/workflows/build-app.yaml @@ -18,9 +18,9 @@ jobs: outputs: architectures: ${{ steps.info.outputs.architectures }} build_matrix: ${{ steps.matrix.outputs.matrix }} - image_name: ${{ steps.split.outputs.image_name }} - registry_prefix: ${{ steps.split.outputs.registry_prefix }} - version: ${{ steps.info.outputs.version }} + image_name: ${{ steps.normalize.outputs.image_name }} + registry_prefix: ${{ steps.normalize.outputs.registry_prefix }} + version: ${{ steps.normalize.outputs.version }} steps: - name: Check out the repository uses: actions/checkout@v6.0.2 @@ -31,20 +31,23 @@ jobs: with: path: "./${{ inputs.app }}" - - name: Split image name - id: split + - name: Normalize app information + id: normalize run: | image="${{ steps.info.outputs.image }}" echo "image_name=${image##*/}" >> "$GITHUB_OUTPUT" echo "registry_prefix=${image%/*}" >> "$GITHUB_OUTPUT" + # Strip surrounding quotes that the info action includes from YAML string values + version="${{ steps.info.outputs.version }}" + echo "version=${version//[\"\']/}" >> "$GITHUB_OUTPUT" - name: Prepare build matrix id: matrix uses: home-assistant/builder/actions/prepare-multi-arch-matrix@2026.03.2 with: architectures: ${{ steps.info.outputs.architectures }} - image-name: ${{ steps.split.outputs.image_name }} - registry-prefix: ${{ steps.split.outputs.registry_prefix }} + image-name: ${{ steps.normalize.outputs.image_name }} + registry-prefix: ${{ steps.normalize.outputs.registry_prefix }} build: name: Build ${{ matrix.arch }} ${{ inputs.app }} From 33b71796a6cd9a068ec0d5e01e24b7dde4018efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cerm=C3=A1k?= Date: Tue, 24 Mar 2026 18:25:48 +0100 Subject: [PATCH 4/4] Improve matrix job names --- .github/workflows/build-app.yaml | 4 ++-- .github/workflows/builder.yaml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-app.yaml b/.github/workflows/build-app.yaml index aa16de91..1f89611b 100644 --- a/.github/workflows/build-app.yaml +++ b/.github/workflows/build-app.yaml @@ -12,7 +12,7 @@ on: jobs: prepare: - name: Prepare ${{ inputs.app }} + name: Prepare if: github.repository == 'home-assistant/apps-example' runs-on: ubuntu-latest outputs: @@ -50,7 +50,7 @@ jobs: registry-prefix: ${{ steps.normalize.outputs.registry_prefix }} build: - name: Build ${{ matrix.arch }} ${{ inputs.app }} + name: Build ${{ matrix.arch }} image needs: prepare runs-on: ${{ matrix.os }} permissions: diff --git a/.github/workflows/builder.yaml b/.github/workflows/builder.yaml index e13e96ed..5ba31ebf 100644 --- a/.github/workflows/builder.yaml +++ b/.github/workflows/builder.yaml @@ -63,6 +63,7 @@ jobs: fi build-app: + name: Build ${{ matrix.app }} needs: init if: needs.init.outputs.changed == 'true' permissions: