Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "Example devcontainer for add-on repositories",
"image": "ghcr.io/home-assistant/devcontainer:2-addons",
"appPort": ["7123:8123", "7357:4357"],
"postStartCommand": "bash devcontainer_bootstrap",
"runArgs": ["-e", "GIT_EDITOR=code --wait", "--privileged"],
"containerEnv": {
"WORKSPACE_DIRECTORY": "${containerWorkspaceFolder}"
},
"workspaceFolder": "/mnt/supervisor/addons/local/${localWorkspaceFolderBasename}",
"workspaceMount": "source=${localWorkspaceFolder},target=${containerWorkspaceFolder},type=bind,consistency=cached",
"customizations": {
"vscode": {
"extensions": ["timonwong.shellcheck", "esbenp.prettier-vscode"],
"settings": {
"terminal.integrated.profiles.linux": {
"zsh": {
"path": "/usr/bin/zsh"
}
},
"terminal.integrated.defaultProfile.linux": "zsh",
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"files.trimTrailingWhitespace": true
}
}
},
"mounts": [
"type=volume,target=/var/lib/docker",
"type=volume,target=/mnt/supervisor"
]
}
4 changes: 2 additions & 2 deletions .github/dependabot.yml → .github/dependabot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
target-branch: dev
interval: weekly
time: "06:00"
121 changes: 121 additions & 0 deletions .github/workflows/builder.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
name: Builder

env:
BUILD_ARGS: "--test"
MONITORED_FILES: "build.yaml config.yaml Dockerfile rootfs"
REGISTRY: ghcr.io

on:
push:
branches:
- master
pull_request:
branches:
- master

permissions:
contents: read

jobs:
init:
runs-on: ubuntu-latest
name: Initialize builds
outputs:
changed_addons: ${{ steps.changed_addons.outputs.addons }}
changed: ${{ steps.changed_addons.outputs.changed }}
steps:
- name: Check out the repository
uses: actions/checkout@v6

- name: Get changed files
id: changed_files
uses: tj-actions/changed-files@v47

- name: Find add-on directories
id: addons
uses: home-assistant/actions/helpers/find-addons@master

- name: Get changed add-ons
id: changed_addons
run: |
declare -a changed_addons
for addon in ${{ steps.addons.outputs.addons }}; do
if [[ "${{ steps.changed_files.outputs.all_changed_files }}" =~ $addon ]]; then
for file in ${{ env.MONITORED_FILES }}; do
if [[ "${{ steps.changed_files.outputs.all_changed_files }}" =~ $addon/$file ]]; then
if [[ ! "${changed_addons[@]}" =~ $addon ]]; then
changed_addons+=("\"${addon}\",");
fi
fi
done
fi
done

changed=$(echo ${changed_addons[@]} | rev | cut -c 2- | rev)

if [[ -n ${changed} ]]; then
echo "Changed add-ons: $changed";
echo "changed=true" >> $GITHUB_OUTPUT;
echo "addons=[$changed]" >> $GITHUB_OUTPUT;
else
echo "No add-on had any monitored files changed (${{ env.MONITORED_FILES }})";
fi

build:
needs: init
runs-on: ubuntu-latest
if: needs.init.outputs.changed == 'true'
name: Build ${{ matrix.arch }} ${{ matrix.addon }} add-on
strategy:
matrix:
addon: ${{ fromJson(needs.init.outputs.changed_addons) }}
arch: ["aarch64", "amd64"]
permissions:
contents: read
packages: write
steps:
- name: Check out repository
uses: actions/checkout@v6

- name: Get information
id: info
uses: home-assistant/actions/helpers/info@master
with:
path: "./${{ matrix.addon }}"

- name: Check if add-on 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@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build ${{ matrix.addon }} add-on
if: steps.check.outputs.build_arch == 'true'
uses: home-assistant/builder@2025.11.0
with:
args: |
${{ env.BUILD_ARGS }} \
--${{ matrix.arch }} \
--target /data/${{ matrix.addon }} \
--image "${{ steps.check.outputs.image }}" \
--docker-hub "${{ env.REGISTRY }}/${{ github.repository_owner }}" \
--addon
73 changes: 73 additions & 0 deletions .github/workflows/bump-version.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: Bump version

on:
workflow_dispatch:
inputs:
addon_folder:
description: "The folder of the add-on to version bump"
required: true
default: "zigbee2mqtt"
type: choice
options: ["zigbee2mqtt"]
arg_name:
description: "The name of the version to bump (without '_VERSION')"
required: true
default: "ZIGBEE2MQTT"
type: string
version:
description: "The new version"
required: true
type: string
changelog:
description: "The changelog to write if needed"
type: string

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
name: Bump ${{ inputs.addon_folder }} add-on ${{ inputs.arg_name }} to ${{ inputs.version }}
permissions:
contents: write
pull-requests: write
steps:
- name: Check out repository
uses: actions/checkout@v6

- name: Bump version & write changelog
run: |
sed -i -E 's/^ ${{ inputs.arg_name }}_VERSION: .*$/ ${{ inputs.arg_name }}_VERSION: "${{ inputs.version }}"/g' ./${{ inputs.addon_folder }}/build.yaml

addonFolderLower=$(echo "${{ inputs.addon_folder }}" | tr '[:upper:]' '[:lower:]')
argNameLower=$(echo "${{ inputs.arg_name }}" | tr '[:upper:]' '[:lower:]')

if [[ "$addonFolderLower" == "$argNameLower" ]]; then
sed -i -E 's/^version: .*$/version: "${{ inputs.version }}"/g' ./${{ inputs.addon_folder }}/config.yaml
fi

if [[ -z "${{ inputs.changelog }}" ]]; then
echo "No changelog to write"
else
echo -e "${{ inputs.changelog }}\n\n$(cat ./${{ inputs.addon_folder }}/CHANGELOG.md)" > ./${{ inputs.addon_folder }}/CHANGELOG.md
fi

branch="${{ inputs.addon_folder }}-${{ inputs.arg_name }}-${{ inputs.version }}"
title="fix: bump ${{ inputs.addon_folder }} add-on ${{ inputs.arg_name }} to ${{ inputs.version }}"

git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
git checkout -b "$branch"
git add .
git commit -m "$title" || echo 'Nothing to commit'
git push origin "$branch"

echo -e "${{ inputs.changelog }}" | gh pr create \
--fill \
--base master \
--head $branch \
--title "$title" \
--body-file -
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
120 changes: 54 additions & 66 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ on:
workflow_dispatch:
inputs:
type:
description: 'Type (edge/proxy)'
default: 'edge'
description: "Type (edge/proxy)"
default: "edge"
required: true

jobs:
Expand All @@ -18,34 +18,24 @@ jobs:
ADDON_LIST: ${{ env.ADDON_LIST }}
BUILD_ARGS: ${{ env.BUILD_ARGS }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v3

- name: "ARGS: default"
run: |
echo "ADDON_LIST=['zigbee2mqtt', 'zigbee2mqtt-edge']" >> $GITHUB_ENV
echo "BUILD_ARGS=--no-latest --test" >> $GITHUB_ENV
- name: "ARGS: zigbee2mqtt-proxy" # Build of addon proxy version
if: github.ref == 'refs/heads/master' && (github.event_name == 'workflow_dispatch' && github.event.inputs.type == 'proxy')
run: |
echo "ADDON_LIST=['zigbee2mqtt-proxy']" >> $GITHUB_ENV
echo "BUILD_ARGS=--no-cache" >> $GITHUB_ENV
- name: "ARGS: zigbee2mqtt-edge" # Build of addon edge version
if: github.ref == 'refs/heads/master' && (github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.type == 'edge'))
run: |
echo "ADDON_LIST=['zigbee2mqtt-edge']" >> $GITHUB_ENV
echo "BUILD_ARGS=--no-cache" >> $GITHUB_ENV
- name: "ARGS: zigbee2mqtt" # Build of addon release version
if: startsWith(github.ref, 'refs/tags/') && github.event_name == 'push'
run: |
echo "ADDON_LIST=['zigbee2mqtt']" >> $GITHUB_ENV
echo "BUILD_ARGS=--no-cache --docker-hub-check" >> $GITHUB_ENV
- name: "ARGS: default"
run: |
echo "ADDON_LIST=['zigbee2mqtt']" >> $GITHUB_ENV
echo "BUILD_ARGS=--no-latest --test" >> $GITHUB_ENV
- name: "ARGS: zigbee2mqtt" # Build of addon release version
if: startsWith(github.ref, 'refs/tags/') && github.event_name == 'push'
run: |
echo "ADDON_LIST=['zigbee2mqtt']" >> $GITHUB_ENV
echo "BUILD_ARGS=--no-cache --docker-hub-check" >> $GITHUB_ENV

- name: Determine arch
id: determine_arch
run: |
ARCH_LIST=$(jq -r -c '.arch' ./${{ fromJSON(env.ADDON_LIST)[0] }}/config.json)
echo "Found the following arches: $ARCH_LIST"
echo "ARCH_LIST=$ARCH_LIST" >> $GITHUB_ENV
- name: Determine arch
id: determine_arch
run: |
ARCH_LIST=$(jq -r -c '.arch' ./${{ fromJSON(env.ADDON_LIST)[0] }}/config.json)
echo "Found the following arches: $ARCH_LIST"
echo "ARCH_LIST=$ARCH_LIST" >> $GITHUB_ENV

build:
runs-on: ubuntu-latest
Expand All @@ -57,54 +47,52 @@ jobs:
arch: ${{fromJSON(needs.variables.outputs.ARCH_LIST)}}
addon: ${{fromJSON(needs.variables.outputs.ADDON_LIST)}}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v3

- name: Log in to docker.io
if: (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
uses: docker/login-action@v3
with:
- name: Log in to docker.io
if: (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
uses: docker/login-action@v3
with:
username: koenkk
password: ${{ secrets.DOCKER_KEY }}

- name: Log in to ghcr.io
if: (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
uses: docker/login-action@v3
with:
- name: Log in to ghcr.io
if: (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
uses: docker/login-action@v3
with:
registry: ghcr.io
username: koenkk
password: ${{ secrets.GH_TOKEN }}

- name: Prepare data folder
run: |
if [ "${{ matrix.addon }}" != "zigbee2mqtt-proxy" ]; then
- name: Prepare data folder
run: |
cp -R common/rootfs ${{ matrix.addon }}
cp common/Dockerfile ${{ matrix.addon }}
fi
cp common/build.yaml ${{ matrix.addon }}
cp common/build.yaml ${{ matrix.addon }}

- name: Build
uses: home-assistant/builder@master
# Note: if running without `--test`, image is pushed to docker.io
with:
args: |
--${{ matrix.arch }} \
--target ${{ matrix.addon }} \
${{ env.BUILD_ARGS }}
- name: Build
uses: home-assistant/builder@master
# Note: if running without `--test`, image is pushed to docker.io
with:
args: |
--${{ matrix.arch }} \
--target ${{ matrix.addon }} \
${{ env.BUILD_ARGS }}

# Keep pushing to docker.io as it is unclear how
# HA handles config.json updates (especially for the unversioned edge)
- name: Push to docker.io
if: (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
run: |
CONFIG_IMAGE=$(cat ${{ matrix.addon }}/config.json | jq -r '.image | sub("{arch}"; "${{ matrix.arch }}")')
CONFIG_VERSION=$(cat ${{ matrix.addon }}/config.json | jq -r .version)
# Keep pushing to docker.io as it is unclear how
# HA handles config.json updates (especially for the unversioned edge)
- name: Push to docker.io
if: (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
run: |
CONFIG_IMAGE=$(cat ${{ matrix.addon }}/config.json | jq -r '.image | sub("{arch}"; "${{ matrix.arch }}")')
CONFIG_VERSION=$(cat ${{ matrix.addon }}/config.json | jq -r .version)

VERSIONS=("latest" "$CONFIG_VERSION")
for VERSION in "${VERSIONS[@]}"; do
GHCR_IMAGE="$CONFIG_IMAGE:$CONFIG_VERSION"
DOCKER_IO_IMAGE=$(echo "$GHCR_IMAGE" | sed 's|ghcr\.io\/||')
echo "Push: $GHCR_IMAGE -> $DOCKER_IO_IMAGE"
docker pull $GHCR_IMAGE
docker tag $GHCR_IMAGE $DOCKER_IO_IMAGE
docker push $DOCKER_IO_IMAGE
done
VERSIONS=("latest" "$CONFIG_VERSION")
for VERSION in "${VERSIONS[@]}"; do
GHCR_IMAGE="$CONFIG_IMAGE:$CONFIG_VERSION"
DOCKER_IO_IMAGE=$(echo "$GHCR_IMAGE" | sed 's|ghcr\.io\/||')
echo "Push: $GHCR_IMAGE -> $DOCKER_IO_IMAGE"
docker pull $GHCR_IMAGE
docker tag $GHCR_IMAGE $DOCKER_IO_IMAGE
docker push $DOCKER_IO_IMAGE
done
Loading
Loading