Build Home Assistant Turbo workflow (ha-china/HAOS-CN)
The Build Home Assistant Turbo workflow from ha-china/HAOS-CN, explained and optimized by Latchkey.
CI health: B - good
Point runs-on at Latchkey and get job timeouts, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Build Home Assistant Turbo workflow from the ha-china/HAOS-CN repository, a real project running GitHub Actions. It is shown here with attribution under its Apache-2.0 license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: Build Home Assistant Turbo
on:
workflow_dispatch:
inputs:
targets:
description: 'Targets to build (comma separated)'
required: false
default: 'rpi3_64,rpi4_64,rpi5_64,ova,generic_x86_64,generic_aarch64,green,yellow,panther_x2,orangepi_cm4'
# schedule:
# - cron: '0 18 26 * *'
# watch:
# types: [started]
#env:
# RUN_VALIDATION: true
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- id: set-matrix
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
TARGETS="${{ github.event.inputs.targets }}"
else
TARGETS="rpi3_64,rpi4_64,rpi5_64,ova,generic_x86_64,generic_aarch64,green,yellow,panther_x2,orangepi_cm4"
fi
JSON=$(echo "$TARGETS" | jq -R -c 'split(",")')
echo "matrix=$JSON" >> $GITHUB_OUTPUT
permissions:
contents: read
pull-requests: read
packages: write
build:
needs: prepare
runs-on: ubuntu-latest
permissions:
contents: read
name: Build ${{ matrix.target }}
strategy:
fail-fast: false
matrix:
target: ${{ fromJson(needs.prepare.outputs.matrix) }}
steps:
- name: Echo target
run: echo "Building for ${{ matrix.target }}"
#target: [generic_aarch64,generic_x86_64]
#steps:
- name: Checkout
uses: actions/checkout@v7
- name: Checkout private repo
uses: actions/checkout@v7
with:
repository: desmond-dong/haos-cn-scripts
token: ${{ secrets.GH_PAT }}
path: private
- name: Run only on main
if: github.ref_name == 'main'
id: get_haos_version
run: |
ver=$(curl -s https://api.github.com/repos/home-assistant/operating-system/releases/latest | jq -r '.tag_name')
echo "CURRENT_VERSION=${ver}" >> $GITHUB_ENV
- name: Run only on dev
if: github.ref_name == 'dev'
id: get_haos_version_dev
run: |
ver=$(curl -s https://version.home-assistant.io/dev.json | jq -r '.hassos.ova')
echo "CURRENT_VERSION=${ver}"
echo "CURRENT_VERSION=${ver}" >> $GITHUB_ENV
- name: Initialization environment and Free up disk space
run: |
sudo timedatectl set-timezone "Asia/Shanghai"
chmod +x private/*.sh
sudo private/release_space.sh
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
- name: Clone source code and Change Settings.
run: |
if [ "${GITHUB_REF_NAME}" = "main" ]; then
git clone https://github.com/home-assistant/operating-system.git -b main
else
git clone https://github.com/home-assistant/operating-system.git
fi
cp -r buildroot-external operating-system
cd operating-system
git submodule update --init
- name: Run private build script
run: |
chmod +x private/*.sh
private/haos.sh
env:
MATRIX_TARGET: ${{matrix.target}}
RAUC_CERTIFICATE: ${{ secrets.RAUC_CERTIFICATE }}
RAUC_PRIVATE_KEY: ${{ secrets.RAUC_PRIVATE_KEY }}
- name: Log in to Docker Hub
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build
shell: 'script -q -e -c "bash {0}"'
id: build
run: |
sleep $((RANDOM % 600))
cd operating-system
scripts/enter.sh make ${{matrix.target}}
- name: Set tag and body for release
if: github.ref_name == 'main'
run: |
echo "RELEASE_TAG=${CURRENT_VERSION}" >> $GITHUB_ENV
echo "RELEASE_BODY=为中国地区专门加速的Home Assistant OS,不修改任何系统内的其它任何信息,所有的修改都以加速为目的。公众号:老王杂谈说,欢迎关注" >> $GITHUB_ENV
- name: Set tag and body for dev release
if: github.ref_name != 'main'
run: |
echo "RELEASE_TAG=dev-${CURRENT_VERSION}" >> $GITHUB_ENV
echo "RELEASE_BODY=此为开发版,请不要当正式版使用" >> $GITHUB_ENV
- name: Upload images to release
id: upload-release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.UPLOAD_TOKEN }}
file: operating-system/output/images/haos_*
tag: ${{ env.RELEASE_TAG }}
overwrite: true
file_glob: true
body: ${{ env.RELEASE_BODY }}
prerelease: ${{ github.ref != 'refs/heads/main' }}
trigger-full-images:
needs: build
if: github.ref_name == 'main'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Dispatch full image workflow
env:
GH_TOKEN: ${{ secrets.GH_PAT }}
CHANNEL: stable
run: |
curl -L -X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${GH_TOKEN}" \
https://api.github.com/repos/ha-china/operating-system-full-images/actions/workflows/build-channel.yml/dispatches \
-d "{\"ref\":\"main\",\"inputs\":{\"channel\":\"${CHANNEL}\"}}"
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: Build Home Assistant Turbo on: workflow_dispatch: inputs: targets: description: 'Targets to build (comma separated)' required: false default: 'rpi3_64,rpi4_64,rpi5_64,ova,generic_x86_64,generic_aarch64,green,yellow,panther_x2,orangepi_cm4' # schedule: # - cron: '0 18 26 * *' # watch: # types: [started] #env: # RUN_VALIDATION: true jobs: prepare: timeout-minutes: 30 runs-on: latchkey-small outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - id: set-matrix run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then TARGETS="${{ github.event.inputs.targets }}" else TARGETS="rpi3_64,rpi4_64,rpi5_64,ova,generic_x86_64,generic_aarch64,green,yellow,panther_x2,orangepi_cm4" fi JSON=$(echo "$TARGETS" | jq -R -c 'split(",")') echo "matrix=$JSON" >> $GITHUB_OUTPUT permissions: contents: read pull-requests: read packages: write build: timeout-minutes: 30 needs: prepare runs-on: latchkey-small permissions: contents: read name: Build ${{ matrix.target }} strategy: fail-fast: false matrix: target: ${{ fromJson(needs.prepare.outputs.matrix) }} steps: - name: Echo target run: echo "Building for ${{ matrix.target }}" #target: [generic_aarch64,generic_x86_64] #steps: - name: Checkout uses: actions/checkout@v7 - name: Checkout private repo uses: actions/checkout@v7 with: repository: desmond-dong/haos-cn-scripts token: ${{ secrets.GH_PAT }} path: private - name: Run only on main if: github.ref_name == 'main' id: get_haos_version run: | ver=$(curl -s https://api.github.com/repos/home-assistant/operating-system/releases/latest | jq -r '.tag_name') echo "CURRENT_VERSION=${ver}" >> $GITHUB_ENV - name: Run only on dev if: github.ref_name == 'dev' id: get_haos_version_dev run: | ver=$(curl -s https://version.home-assistant.io/dev.json | jq -r '.hassos.ova') echo "CURRENT_VERSION=${ver}" echo "CURRENT_VERSION=${ver}" >> $GITHUB_ENV - name: Initialization environment and Free up disk space run: | sudo timedatectl set-timezone "Asia/Shanghai" chmod +x private/*.sh sudo private/release_space.sh sudo rm -rf "$AGENT_TOOLSDIRECTORY" - name: Clone source code and Change Settings. run: | if [ "${GITHUB_REF_NAME}" = "main" ]; then git clone https://github.com/home-assistant/operating-system.git -b main else git clone https://github.com/home-assistant/operating-system.git fi cp -r buildroot-external operating-system cd operating-system git submodule update --init - name: Run private build script run: | chmod +x private/*.sh private/haos.sh env: MATRIX_TARGET: ${{matrix.target}} RAUC_CERTIFICATE: ${{ secrets.RAUC_CERTIFICATE }} RAUC_PRIVATE_KEY: ${{ secrets.RAUC_PRIVATE_KEY }} - name: Log in to Docker Hub uses: docker/login-action@v4 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build shell: 'script -q -e -c "bash {0}"' id: build run: | sleep $((RANDOM % 600)) cd operating-system scripts/enter.sh make ${{matrix.target}} - name: Set tag and body for release if: github.ref_name == 'main' run: | echo "RELEASE_TAG=${CURRENT_VERSION}" >> $GITHUB_ENV echo "RELEASE_BODY=为中国地区专门加速的Home Assistant OS,不修改任何系统内的其它任何信息,所有的修改都以加速为目的。公众号:老王杂谈说,欢迎关注" >> $GITHUB_ENV - name: Set tag and body for dev release if: github.ref_name != 'main' run: | echo "RELEASE_TAG=dev-${CURRENT_VERSION}" >> $GITHUB_ENV echo "RELEASE_BODY=此为开发版,请不要当正式版使用" >> $GITHUB_ENV - name: Upload images to release id: upload-release uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.UPLOAD_TOKEN }} file: operating-system/output/images/haos_* tag: ${{ env.RELEASE_TAG }} overwrite: true file_glob: true body: ${{ env.RELEASE_BODY }} prerelease: ${{ github.ref != 'refs/heads/main' }} trigger-full-images: timeout-minutes: 30 needs: build if: github.ref_name == 'main' runs-on: latchkey-small permissions: contents: read steps: - name: Dispatch full image workflow env: GH_TOKEN: ${{ secrets.GH_PAT }} CHANNEL: stable run: | curl -L -X POST \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer ${GH_TOKEN}" \ https://api.github.com/repos/ha-china/operating-system-full-images/actions/workflows/build-channel.yml/dispatches \ -d "{\"ref\":\"main\",\"inputs\":{\"channel\":\"${CHANNEL}\"}}"
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Add a job timeout so a hung step cannot burn hours of runner time.
2 third-party actions are referenced by a movable tag. Pin them to the commit SHA (Latchkey resolves and applies this automatically) so a repointed tag cannot change what runs.
What Latchkey heals here
This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:
- Network fetches
This workflow runs 3 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.